aboutsummaryrefslogtreecommitdiff
path: root/core/operator/keyed_process.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/operator/keyed_process.go')
-rw-r--r--core/operator/keyed_process.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/core/operator/keyed_process.go b/core/operator/keyed_process.go
new file mode 100644
index 0000000..1d3c86c
--- /dev/null
+++ b/core/operator/keyed_process.go
@@ -0,0 +1,81 @@
1package operator
2
3import (
4 "context"
5 "flux/core"
6 "fmt"
7)
8
9type KeyedProcesser[IN, OUT any] interface {
10 Open(ctx context.Context) error
11 ProcessElement(ctx context.Context, record core.StreamRecord[IN], out Emitter[OUT]) error
12 Close(ctx context.Context) error
13 OnTimer(ctx context.Context, timestamp int64, out Emitter[OUT]) error
14}
15
16type KeyProcessOperator[IN, OUT any] struct {
17 userFunc KeyedProcesser[IN, OUT]
18 timeService core.InternalTimerService
19 backend core.StateBackend
20}
21
22func NewKeyProcessOperator[IN, OUT any](userFunc KeyedProcesser[IN, OUT]) *KeyProcessOperator[IN, OUT] {
23 return &KeyProcessOperator[IN, OUT]{
24 userFunc: userFunc,
25 timeService: core.NewTimerService(),
26 }
27}
28
29func (k *KeyProcessOperator[IN, OUT]) Open(ctx context.Context) error {
30 // init backend
31 be, ok := core.ExtractStateBackend(ctx)
32 if !ok {
33 return fmt.Errorf("state backend not found")
34 }
35
36 k.backend = be
37 // inject the timer to context for user use
38 ctx = core.InjectTimerService(ctx, k.timeService)
39 return k.userFunc.Open(ctx)
40
41}
42
43func (k *KeyProcessOperator[IN, OUT]) Process(ctx context.Context, record core.StreamRecord[IN], out Emitter[OUT]) error {
44
45 switch record.Type {
46 case core.RecordData:
47 if err := k.backend.SetCurrentKey(record.Key); err != nil {
48 return err
49 }
50
51 return k.userFunc.ProcessElement(ctx, record, out)
52 case core.RecordWatermark:
53 // advance the timer
54 triggerTimerQueue := k.timeService.AdvanceWatermark(record.Timestamp)
55
56 for _, t := range triggerTimerQueue {
57
58 if err := k.backend.SetCurrentKey(t.Key); err != nil {
59 return err
60 }
61 if err := k.userFunc.OnTimer(ctx, t.Timestamp, out); err != nil {
62 return err
63 }
64 }
65 return out.Emit(ctx, core.StreamRecord[OUT]{
66 Type: core.RecordWatermark,
67 Timestamp: record.Timestamp,
68 })
69 default:
70 return out.Emit(ctx, core.StreamRecord[OUT]{
71 Timestamp: record.Timestamp,
72 BarrierID: record.BarrierID,
73 Key: record.Key,
74 })
75 }
76
77}
78
79func (k *KeyProcessOperator[IN, OUT]) Close(ctx context.Context) error {
80 return k.userFunc.Close(ctx)
81}