window
Package window stores the last N event values for an entity and computes exact
client-side aggregations over that bounded list. It is useful for features such
as "average amount over the last 10 events" where event count, not wall-clock
time, defines the window.
A *client.Client can be passed directly to Execute, Read, and Delete.
The package stores records in set window and uses a single list bin
internally. WindowSize must be between 1 and MaxWindowSize (100).
Strengths
- The helper is intentionally small:
Execute and Read need only Operate,
and Delete needs only Delete, so tests can use narrow mocks.
- Storage is easy to reason about. Each entity scope maps to one deterministic
key in set
window, derived from Name, Ref, the source value for Ref,
and GroupBy values.
GroupBy order does not affect the key, which helps when callers construct
equivalent requests from maps or configuration.
- Aggregations are exact over the retained values. There are no HLL or TDigest
sketches in this helper; percentile calculation sorts the retained values and
uses linear interpolation.
MaxWindowSize bounds each list to at most 100 retained values, keeping read,
decode, and aggregation work predictable for last-N features.
Weaknesses / Tradeoffs
- This is a count-based last-N window, not a time-range query. Event timestamps
are stored with entries, but reads aggregate by list contents and trimming
removes the oldest appended entries, not entries older than a timestamp.
TTL applies to the whole window record and is refreshed by writes. It does
not expire individual entries inside the list.
- Every read decodes the retained list and computes aggregations client-side.
That is exact and simple, but it is intentionally capped at
MaxWindowSize
rather than designed for large windows.
- The window result implements count, sum, min, max, average, sample standard
deviation, and percentile. Other
queries.Field flags, such as distinct,
geometric mean, and circular mean, are not returned by this helper.
- List uniqueness applies to the full serialized entry
[EventID, value, timestamp]. Replays need the same value and event timestamp
to serialize identically; EventID is stored but not validated as a separate
uniqueness key.
- Missing or non-numeric
Value fields read as 0 with MapSource.
Request
Important request fields:
Name: variable name used in key derivation.
Namespace: FrogoDB namespace.
Ref: source key for the reference entity, such as a user ID.
GroupBy: optional source keys that further scope the entity.
Value: source key for the numeric value appended to the window.
WindowSize: number of recent events to keep, from 1 through 100.
Fields: aggregation flags from package queries.
PercentileP: percentile for FieldPercentile, expressed from 0 to 1.
EventID: current event ID stored with each appended entry.
TTL: required positive expiration duration.
IncludeCurrent: when true, write before reading; when false, read before
writing.
Ref, Value, WindowSize, and TTL are validated. The deterministic key is
derived from Name, Ref, the source value for Ref, and GroupBy values.
GroupBy order does not affect the key.
Example
func updateWindow(ctx context.Context) error {
c, err := client.New("127.0.0.1:3000")
if err != nil {
return err
}
defer c.Close()
src := queries.NewMapSource(map[string]any{
"event_id": "evt-123",
"standard.user_id": "user-42",
"amount": 42.5,
"event_time": time.Now(),
})
req := window.Request{
Name: "user_last_10_amounts",
Namespace: "scoring",
Ref: "standard.user_id",
Value: "amount",
WindowSize: 10,
Fields: queries.FieldCount | queries.FieldAvg | queries.FieldSTD | queries.FieldPercentile,
PercentileP: 0.90,
EventID: src.String("event_id"),
TTL: 24 * time.Hour,
IncludeCurrent: true,
}
result, err := window.Execute(ctx, c, req, src)
if err != nil {
return err
}
_ = result.Count
_ = result.Avg
_ = result.Percentile
return nil
}
Use Read to compute the current window without appending the event:
result, err := window.Read(ctx, c, req, src)
Use Delete to remove the stored window for the same request and source scope:
err := window.Delete(ctx, c, req, src)
Behavior
Execute writes and reads in the order selected by IncludeCurrent.
IncludeCurrent: true: append the current event, trim excess entries, then
read and aggregate the updated list.
IncludeCurrent: false: read and aggregate existing entries, then append the
current event.
Writes append entries with EventID, numeric value, and event timestamp. The
append uses the client's unique/no-fail list flags for exact serialized entry
matches. When the list grows past WindowSize, the oldest entries are removed
from the beginning.
Result includes Count, Sum, Min, Max, Avg, STD, Percentile, and
Values. Window math is exact over the retained values. Percentiles use linear
interpolation and clamp PercentileP to the 0 to 1 range.
Event timestamps come from queries.EventTime(src), so event_time may be a
time.Time, int64 Unix seconds, or int Unix seconds. If omitted, the helper
uses time.Now().