Skip to content

Commit a52f25d

Browse files
authored
During eviction, set is_replaying and raise special exception (#524)
Fixes #523
1 parent f96679b commit a52f25d

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,3 @@ jobs:
105105
python-repo-path: ${{github.event.pull_request.head.repo.full_name}}
106106
version: ${{github.event.pull_request.head.ref}}
107107
version-is-repo-ref: true
108-
features-repo-ref: http-connect-proxy-python

temporalio/worker/_workflow_instance.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,9 @@ def _apply_remove_from_cache(
637637
) -> None:
638638
self._deleting = True
639639
self._cancel_requested = True
640+
# We consider eviction to be under replay so that certain code like
641+
# logging that avoids replaying doesn't run during eviction either
642+
self._is_replaying = True
640643
# Cancel everything
641644
for task in self._tasks:
642645
task.cancel()
@@ -1514,7 +1517,9 @@ def _assert_not_read_only(
15141517
self, action_attempted: str, *, allow_during_delete: bool = False
15151518
) -> None:
15161519
if self._deleting and not allow_during_delete:
1517-
raise RuntimeError(f"Ignoring {action_attempted} while deleting")
1520+
raise _WorkflowBeingEvictedError(
1521+
f"Ignoring {action_attempted} while evicting workflow. This is not an error."
1522+
)
15181523
if self._read_only:
15191524
raise temporalio.workflow.ReadOnlyContextError(
15201525
f"While in read-only function, action attempted: {action_attempted}"
@@ -2614,3 +2619,7 @@ def set(
26142619
) -> None:
26152620
if not temporalio.workflow.unsafe.is_replaying():
26162621
self._underlying.set(value, additional_attributes)
2622+
2623+
2624+
class _WorkflowBeingEvictedError(BaseException):
2625+
pass

tests/worker/test_workflow.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3429,6 +3429,52 @@ async def signal_count() -> int:
34293429
assert not hook_calls
34303430

34313431

3432+
@dataclass
3433+
class CapturedEvictionException:
3434+
is_replaying: bool
3435+
exception: BaseException
3436+
3437+
3438+
captured_eviction_exceptions: List[CapturedEvictionException] = []
3439+
3440+
3441+
@workflow.defn(sandboxed=False)
3442+
class EvictionCaptureExceptionWorkflow:
3443+
@workflow.run
3444+
async def run(self) -> None:
3445+
# Going to sleep so we can force eviction
3446+
try:
3447+
await asyncio.sleep(0.01)
3448+
except BaseException as err:
3449+
captured_eviction_exceptions.append(
3450+
CapturedEvictionException(
3451+
is_replaying=workflow.unsafe.is_replaying(), exception=err
3452+
)
3453+
)
3454+
3455+
3456+
async def test_workflow_eviction_exception(client: Client):
3457+
assert not captured_eviction_exceptions
3458+
3459+
# Run workflow with no cache (forces eviction every step)
3460+
async with new_worker(
3461+
client, EvictionCaptureExceptionWorkflow, max_cached_workflows=0
3462+
) as worker:
3463+
await client.execute_workflow(
3464+
EvictionCaptureExceptionWorkflow.run,
3465+
id=f"workflow-{uuid.uuid4()}",
3466+
task_queue=worker.task_queue,
3467+
)
3468+
3469+
# Confirm expected eviction replaying state and exception type
3470+
assert len(captured_eviction_exceptions) == 1
3471+
assert captured_eviction_exceptions[0].is_replaying
3472+
assert (
3473+
type(captured_eviction_exceptions[0].exception).__name__
3474+
== "_WorkflowBeingEvictedError"
3475+
)
3476+
3477+
34323478
@dataclass
34333479
class DynamicWorkflowValue:
34343480
some_string: str

0 commit comments

Comments
 (0)