feat(memory): AW-backed Store with over-fetch kind filtering
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"keel/internal/aw"
|
||||
)
|
||||
|
||||
// Event is one derived event Keel chooses to remember. Kind is the event type
|
||||
@@ -68,3 +70,63 @@ func (f *Fake) Events() []Event {
|
||||
defer f.mu.Unlock()
|
||||
return append([]Event(nil), f.events...)
|
||||
}
|
||||
|
||||
// overfetch bounds how many recent bucket events awStore pulls before filtering
|
||||
// by kind, because keel.events interleaves all kinds. Events older than this
|
||||
// window are not seen — acceptable for "recent".
|
||||
const overfetch = 200
|
||||
|
||||
// kindKey is the data field carrying the Event.Kind inside an AW event.
|
||||
const kindKey = "_kind"
|
||||
|
||||
// AWClient is the subset of *aw.Client that awStore needs. Declaring it here
|
||||
// lets tests inject a fake without HTTP; *aw.Client satisfies it structurally.
|
||||
type AWClient interface {
|
||||
Insert(ctx context.Context, bucketID string, e aw.Event) error
|
||||
Recent(ctx context.Context, bucketID string, limit int) ([]aw.Event, error)
|
||||
}
|
||||
|
||||
type awStore struct {
|
||||
c AWClient
|
||||
bucketID string
|
||||
}
|
||||
|
||||
// NewAWStore returns a Store that persists events to the given AW bucket.
|
||||
func NewAWStore(c AWClient, bucketID string) Store {
|
||||
return &awStore{c: c, bucketID: bucketID}
|
||||
}
|
||||
|
||||
func (s *awStore) Record(ctx context.Context, e Event) error {
|
||||
data := make(map[string]any, len(e.Data)+1)
|
||||
for k, v := range e.Data {
|
||||
data[k] = v
|
||||
}
|
||||
data[kindKey] = e.Kind
|
||||
return s.c.Insert(ctx, s.bucketID, aw.Event{Timestamp: e.At, Duration: 0, Data: data})
|
||||
}
|
||||
|
||||
func (s *awStore) Recent(ctx context.Context, kind string, n int) ([]Event, error) {
|
||||
if n <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
raw, err := s.c.Recent(ctx, s.bucketID, overfetch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []Event
|
||||
for _, ev := range raw {
|
||||
if len(out) >= n {
|
||||
break
|
||||
}
|
||||
if k, _ := ev.Data[kindKey].(string); k == kind {
|
||||
data := make(map[string]any, len(ev.Data))
|
||||
for dk, dv := range ev.Data {
|
||||
if dk != kindKey {
|
||||
data[dk] = dv
|
||||
}
|
||||
}
|
||||
out = append(out, Event{Kind: kind, At: ev.Timestamp, Data: data})
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user