Documentation
¶
Overview ¶
Package cycle computes the billing cycle a node's traffic belongs to.
It exists on the panel side because the panel did not have it. The agent has always computed when its own month resets (`agent/utils.GetLastResetDate`, used by netstatic), but it reports a *cumulative* total without saying which window that total covers — so the panel could compare usage against a limit, which is arithmetic on two numbers it has, but could not ask "how far through the cycle are we", which is what any projection needs.
The rules are a deliberate mirror of the agent's, including the one that looks like an edge case and is not: **a reset day the month does not have rolls forward to the first of the next month.** A node configured for the 31st is reset on the 31st in January and on the 1st in February, and a projection that disagreed with the agent about that would be wrong for one day a month — which is exactly the day a limit tends to be hit. `internal/cycle`'s tests assert the same cases the agent's do, so the two can be compared rather than only trusted.
The location matters as much as the day: the agent resets on its *local* midnight, so a cycle computed in UTC for a node in Asia/Tokyo would be off by nine hours, and a forecast of "how much of the cycle has elapsed" would be wrong by a third of a day every day.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Location ¶
Location resolves a node's timezone name.
An unknown or empty name falls back to UTC rather than failing: a node whose timezone the panel cannot resolve is still a node whose traffic should be watched, and a projection computed in the wrong zone is more useful than no projection — provided the caller can see which zone was used, which is why Cycle carries the name.
Types ¶
type Cycle ¶
type Cycle struct {
// Start is the most recent reset at or before the reference time.
Start time.Time `json:"start"`
// End is the next reset, which is the moment the current cycle's total goes back to zero.
End time.Time `json:"end"`
// ResetDay is the configured day of the month, kept so a reader can see what the boundaries came
// from rather than having to infer it.
ResetDay int `json:"reset_day"`
// Location is the timezone the boundaries were computed in: the node's own, which is where its
// agent resets. Reported as a name so a mismatch is visible.
Location string `json:"location"`
}
Cycle is one billing period, half-open: `[Start, End)`.
Half-open because that is what the agent's reset produces: the instant of the reset belongs to the new cycle, which is why a sample landing exactly on it is counted once rather than twice or not at all. The forecast takes the same convention, so the two agree about the boundary.
func Bounds ¶
Bounds returns the billing cycle containing `reference`, for a node whose month resets on `resetDay` in `location`.
A reset day outside 1..31 means the node has no monthly cycle configured — the agent treats it the same way, returning the reference date itself — and is reported as an error rather than as a one-instant cycle, because a caller that got a zero-length cycle would go on to divide by it.
func (Cycle) Elapsed ¶
Elapsed is how far into the cycle the reference time is, clamped to the cycle.
Clamped rather than computed directly because a caller may hold a report that arrived slightly after the reset: an unclamped elapsed fraction above 1 would make a projection divide by more than the cycle and report a total for a window that has already ended.
type InvalidResetDayError ¶
type InvalidResetDayError struct{ ResetDay int }
InvalidResetDayError reports a day the calendar cannot have.
func (*InvalidResetDayError) Error ¶
func (e *InvalidResetDayError) Error() string