@@ -174,15 +174,25 @@ async def _handle_activation(
174
174
) -> None :
175
175
global LOG_PROTOS
176
176
177
+ # Extract a couple of jobs from the activation
178
+ cache_remove_job = None
179
+ start_job = None
180
+ for job in act .jobs :
181
+ if job .HasField ("remove_from_cache" ):
182
+ cache_remove_job = job .remove_from_cache
183
+ elif job .HasField ("start_workflow" ):
184
+ start_job = job .start_workflow
185
+ cache_remove_only_activation = len (act .jobs ) == 1 and cache_remove_job
186
+
177
187
# Build default success completion (e.g. remove-job-only activations)
178
188
completion = (
179
189
temporalio .bridge .proto .workflow_completion .WorkflowActivationCompletion ()
180
190
)
181
191
completion .successful .SetInParent ()
182
- remove_job = None
183
192
try :
184
- # Decode the activation if there's a codec
185
- if self ._data_converter .payload_codec :
193
+ # Decode the activation if there's a codec and it's not a
194
+ # cache-remove-only activation
195
+ if self ._data_converter .payload_codec and not cache_remove_only_activation :
186
196
await temporalio .bridge .worker .decode_activation (
187
197
act , self ._data_converter .payload_codec
188
198
)
@@ -191,15 +201,21 @@ async def _handle_activation(
191
201
logger .debug ("Received workflow activation:\n %s" , act )
192
202
193
203
# We only have to run if there are any non-remove-from-cache jobs
194
- remove_job = next (
195
- (j for j in act .jobs if j .HasField ("remove_from_cache" )), None
196
- )
197
- if len (act .jobs ) > 1 or not remove_job :
204
+ if not cache_remove_only_activation :
198
205
# If the workflow is not running yet, create it
199
206
workflow = self ._running_workflows .get (act .run_id )
200
207
if not workflow :
201
- workflow = self ._create_workflow_instance (act )
208
+ # Must have a start job to create instance
209
+ if not start_job :
210
+ raise RuntimeError (
211
+ "Missing start workflow, workflow could have unexpectedly been removed from cache"
212
+ )
213
+ workflow = self ._create_workflow_instance (act , start_job )
202
214
self ._running_workflows [act .run_id ] = workflow
215
+ elif start_job :
216
+ # This should never happen
217
+ logger .warn ("Cache already exists for activation with start job" )
218
+
203
219
# Run activation in separate thread so we can check if it's
204
220
# deadlocked
205
221
activate_task = asyncio .get_running_loop ().run_in_executor (
@@ -241,8 +257,25 @@ async def _handle_activation(
241
257
# Always set the run ID on the completion
242
258
completion .run_id = act .run_id
243
259
244
- # Encode the completion if there's a codec
245
- if self ._data_converter .payload_codec :
260
+ # If there is a remove-from-cache job, do so
261
+ if cache_remove_job :
262
+ if act .run_id in self ._running_workflows :
263
+ logger .debug (
264
+ "Evicting workflow with run ID %s, message: %s" ,
265
+ act .run_id ,
266
+ cache_remove_job .message ,
267
+ )
268
+ del self ._running_workflows [act .run_id ]
269
+ else :
270
+ logger .warn (
271
+ "Eviction request on unknown workflow with run ID %s, message: %s" ,
272
+ act .run_id ,
273
+ cache_remove_job .message ,
274
+ )
275
+
276
+ # Encode the completion if there's a codec and it's not a
277
+ # cache-remove-only activation
278
+ if self ._data_converter .payload_codec and not cache_remove_only_activation :
246
279
try :
247
280
await temporalio .bridge .worker .encode_completion (
248
281
completion , self ._data_converter .payload_codec
@@ -265,54 +298,30 @@ async def _handle_activation(
265
298
"Failed completing activation on workflow with run ID %s" , act .run_id
266
299
)
267
300
268
- # If there is a remove-from-cache job, do so
269
- if remove_job :
270
- if act .run_id in self ._running_workflows :
271
- logger .debug (
272
- "Evicting workflow with run ID %s, message: %s" ,
273
- act .run_id ,
274
- remove_job .remove_from_cache .message ,
275
- )
276
- del self ._running_workflows [act .run_id ]
277
- else :
278
- logger .debug (
279
- "Eviction request on unknown workflow with run ID %s, message: %s" ,
280
- act .run_id ,
281
- remove_job .remove_from_cache .message ,
282
- )
283
- # If we are failing on eviction, set the error and shutdown the
284
- # entire worker
285
- if self ._on_eviction_hook is not None :
286
- try :
287
- self ._on_eviction_hook (act .run_id , remove_job .remove_from_cache )
288
- except Exception as e :
289
- self ._throw_after_activation = e
290
- logger .debug ("Shutting down worker on eviction" )
291
- self ._bridge_worker ().initiate_shutdown ()
301
+ # If there is a remove job and an eviction hook, run it
302
+ if cache_remove_job and self ._on_eviction_hook is not None :
303
+ try :
304
+ self ._on_eviction_hook (act .run_id , cache_remove_job )
305
+ except Exception as e :
306
+ self ._throw_after_activation = e
307
+ logger .debug ("Shutting down worker on eviction" )
308
+ self ._bridge_worker ().initiate_shutdown ()
292
309
293
310
def _create_workflow_instance (
294
- self , act : temporalio .bridge .proto .workflow_activation .WorkflowActivation
311
+ self ,
312
+ act : temporalio .bridge .proto .workflow_activation .WorkflowActivation ,
313
+ start : temporalio .bridge .proto .workflow_activation .StartWorkflow ,
295
314
) -> WorkflowInstance :
296
- # First find the start workflow job
297
- start_job = next ((j for j in act .jobs if j .HasField ("start_workflow" )), None )
298
- if not start_job :
299
- raise RuntimeError (
300
- "Missing start workflow, workflow could have unexpectedly been removed from cache"
301
- )
302
-
303
315
# Get the definition
304
- defn = self ._workflows .get (
305
- start_job .start_workflow .workflow_type , self ._dynamic_workflow
306
- )
316
+ defn = self ._workflows .get (start .workflow_type , self ._dynamic_workflow )
307
317
if not defn :
308
318
workflow_names = ", " .join (sorted (self ._workflows .keys ()))
309
319
raise temporalio .exceptions .ApplicationError (
310
- f"Workflow class { start_job . start_workflow .workflow_type } is not registered on this worker, available workflows: { workflow_names } " ,
320
+ f"Workflow class { start .workflow_type } is not registered on this worker, available workflows: { workflow_names } " ,
311
321
type = "NotFoundError" ,
312
322
)
313
323
314
324
# Build info
315
- start = start_job .start_workflow
316
325
parent : Optional [temporalio .workflow .ParentInfo ] = None
317
326
if start .HasField ("parent_workflow_info" ):
318
327
parent = temporalio .workflow .ParentInfo (
0 commit comments