Skip to content

Commit 71962f1

Browse files
committed
fix(testing): race-safe worker submit and shutdown
- Add ExecutionRegistry.submit with compare-and-evict retry so a worker that stops its lane between hand-out and submit no longer surfaces RuntimeError; reorder teardown to stop-then-remove. - Add ExecutionRegistry.shutdown; WebRunner.stop and DurableFunctionTestRunner.close now stop per-execution lanes so they do not outlive the runner. - Honor MaxItems in GetDurableExecutionState, clamped to the service page-count bounds, via the paginator's new count bound. - Remove dead _release_gate and _cleanup_execution_state; fix logger.exception misuse on non-error paths; fix the wait_for_callback timeout message.
1 parent 291a1db commit 71962f1

10 files changed

Lines changed: 302 additions & 185 deletions

File tree

packages/aws-durable-execution-sdk-python-testing/src/aws_durable_execution_sdk_python_testing/client.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@ def checkpoint(
3737
updates: list[OperationUpdate],
3838
client_token: str | None,
3939
) -> CheckpointOutput:
40-
worker = self._registry.get_or_create(durable_execution_arn)
4140
task = CheckpointTask(
4241
self._checkpoint_processor, checkpoint_token, updates, client_token
4342
)
44-
return worker.submit(task).result()
43+
return self._registry.submit(durable_execution_arn, task).result()
4544

4645
def get_execution_state(
4746
self,
@@ -50,11 +49,10 @@ def get_execution_state(
5049
next_marker: str,
5150
max_items: int = 1000,
5251
) -> StateOutput:
53-
worker = self._registry.get_or_create(durable_execution_arn)
5452
task = GetStateTask(
5553
self._checkpoint_processor, checkpoint_token, next_marker, max_items
5654
)
57-
return worker.submit(task).result()
55+
return self._registry.submit(durable_execution_arn, task).result()
5856

5957
def stop(self, execution_arn: str, payload: bytes | None) -> datetime.datetime: # noqa: ARG002
6058
# TODO: implement

packages/aws-durable-execution-sdk-python-testing/src/aws_durable_execution_sdk_python_testing/execution.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -637,12 +637,16 @@ def page(
637637
self,
638638
marker: str | None,
639639
max_size_bytes: int,
640+
max_items: int | None = None,
640641
) -> tuple[list[Operation], str | None]:
641642
"""Return a page of ops starting after ``marker``, bounded by
642-
``max_size_bytes``. Second element of the tuple is a marker for
643-
the next page, or ``None`` when the page fits everything."""
643+
``max_size_bytes`` and, when given, ``max_items``. Second element
644+
of the tuple is a marker for the next page, or ``None`` when the
645+
page fits everything."""
644646
start_idx = self._resolve_marker(marker)
645-
return self._walk_page(self.snapshot_operations, start_idx, max_size_bytes)
647+
return self._walk_page(
648+
self.snapshot_operations, start_idx, max_size_bytes, max_items
649+
)
646650

647651
def unseen_operations(self) -> list[Operation]:
648652
"""Operations whose ``operation_last_touched_seq`` is strictly
@@ -675,13 +679,16 @@ def _walk_page(
675679
ops: list[Operation],
676680
start_idx: int,
677681
max_size_bytes: int,
682+
max_items: int | None = None,
678683
) -> tuple[list[Operation], str | None]:
679684
selected: list[Operation] = []
680685
total = 0
681686
for i in range(start_idx, len(ops)):
682687
op = ops[i]
683688
size = self._size_for(op)
684-
if selected and total + size > max_size_bytes:
689+
over_bytes: bool = total + size > max_size_bytes
690+
over_count: bool = max_items is not None and len(selected) >= max_items
691+
if selected and (over_bytes or over_count):
685692
return selected, self._encode_marker(i)
686693
selected.append(op)
687694
total += size

0 commit comments

Comments
 (0)