1414 _AccumulatorBuilderClass ,
1515 AccumulatorAsyncCallable ,
1616 WindowOperation ,
17+ AccumulatorRequest ,
1718)
1819from pynumaflow .proto .accumulator import accumulator_pb2
1920from pynumaflow .shared .asynciter import NonBlockingIterator
@@ -93,7 +94,7 @@ async def stream_send_eof(self):
9394 for unified_key in task_keys :
9495 await self .tasks [unified_key ].iterator .put (STREAM_EOF )
9596
96- async def close_task (self , req ):
97+ async def close_task (self , req : AccumulatorRequest ):
9798 """
9899 Closes a running accumulator task for a given key.
99100 Based on the request we compute the unique key, and then
@@ -104,8 +105,9 @@ async def close_task(self, req):
104105 3. Wait for all the results from the task to be written to the global result queue
105106 4. Remove the task from the tracker
106107 """
107- d = req .payload
108- keys = d .keys
108+ # Use keyed_window.keys for task lookup since payload.keys may be empty
109+ # (e.g., CLOSE operations don't carry data, so payload.keys is not populated).
110+ keys = req .keyed_window .keys
109111 unified_key = build_unique_key_name (keys )
110112 curr_task = self .tasks .get (unified_key , None )
111113
@@ -120,14 +122,16 @@ async def close_task(self, req):
120122 # Put the exception in the result queue
121123 await self .global_result_queue .put (err )
122124
123- async def create_task (self , req ):
125+ async def create_task (self , req : AccumulatorRequest ):
124126 """
125127 Creates a new accumulator task for the given request.
126128 Based on the request we compute a unique key, and then
127129 it creates a new task or appends the request to the existing task.
128130 """
129131 d = req .payload
130- keys = d .keys
132+ # Use keyed_window.keys for task lookup — the authoritative key identity
133+ # for the window, consistent across all operation types (OPEN, APPEND, CLOSE).
134+ keys = req .keyed_window .keys
131135 unified_key = build_unique_key_name (keys )
132136 curr_task = self .tasks .get (unified_key , None )
133137
@@ -138,7 +142,7 @@ async def create_task(self, req):
138142 # Create a new result queue for the current task
139143 # We create a new result queue for each task, so that
140144 # the results of the accumulator operation can be sent to the
141- # the global result queue, which in turn sends the results
145+ # global result queue, which in turn sends the results
142146 # to the client.
143147 res_queue = NonBlockingIterator ()
144148
@@ -172,13 +176,14 @@ async def create_task(self, req):
172176 # Put the request in the iterator
173177 await curr_task .iterator .put (d )
174178
175- async def send_datum_to_task (self , req ):
179+ async def send_datum_to_task (self , req : AccumulatorRequest ):
176180 """
177181 Appends the request to the existing window reduce task.
178182 If the task does not exist, create it.
179183 """
180184 d = req .payload
181- keys = d .keys
185+ # Use keyed_window.keys for task lookup to match the key used in create_task/close_task.
186+ keys = req .keyed_window .keys
182187 unified_key = build_unique_key_name (keys )
183188 result = self .tasks .get (unified_key , None )
184189 if not result :
@@ -215,9 +220,7 @@ async def __invoke_accumulator(
215220 # Put the exception in the result queue
216221 await self .global_result_queue .put (err )
217222
218- async def process_input_stream (
219- self , request_iterator : AsyncIterable [accumulator_pb2 .AccumulatorRequest ]
220- ):
223+ async def process_input_stream (self , request_iterator : AsyncIterable [AccumulatorRequest ]):
221224 # Start iterating through the request iterator and create tasks
222225 # based on the operation type received.
223226 try :
@@ -226,15 +229,15 @@ async def process_input_stream(
226229 request_count += 1
227230 # check whether the request is an open, append, or close operation
228231 match request .operation :
229- case int ( WindowOperation .OPEN ) :
232+ case WindowOperation .OPEN :
230233 # create a new task for the open operation and
231234 # put the request in the task iterator
232235 await self .create_task (request )
233- case int ( WindowOperation .APPEND ) :
236+ case WindowOperation .APPEND :
234237 # append the task data to the existing task
235238 # if the task does not exist, create a new task
236239 await self .send_datum_to_task (request )
237- case int ( WindowOperation .CLOSE ) :
240+ case WindowOperation .CLOSE :
238241 # close the current task for req
239242 await self .close_task (request )
240243 case _:
0 commit comments