|
4 | 4 | import math |
5 | 5 | import sys |
6 | 6 | import warnings |
7 | | -from contextlib import contextmanager |
8 | 7 | from dataclasses import asdict |
9 | 8 | from datetime import UTC, datetime, timedelta |
10 | 9 | from functools import cached_property |
|
42 | 41 |
|
43 | 42 | if TYPE_CHECKING: |
44 | 43 | import logging |
45 | | - from collections.abc import Callable, Iterator, MutableMapping |
| 44 | + from collections.abc import Callable, MutableMapping |
46 | 45 | from decimal import Decimal |
47 | 46 | from types import TracebackType |
48 | 47 | from typing import Self |
@@ -288,15 +287,12 @@ async def finalize() -> None: |
288 | 287 | except Exception: |
289 | 288 | self.log.exception('Failed to save Actor state') |
290 | 289 |
|
291 | | - # `exit()` / `fail()` may be called from within an event listener; detach that listener's own task for |
292 | | - # the duration of the cleanup so the waits below don't deadlock on it (see `_detach_current_listener_task`). |
293 | | - with self._detach_current_listener_task(): |
294 | | - try: |
295 | | - await asyncio.wait_for(finalize(), self._cleanup_timeout.total_seconds()) |
296 | | - except TimeoutError: |
297 | | - self.log.exception('Actor cleanup timed out') |
298 | | - finally: |
299 | | - self._active = False |
| 290 | + try: |
| 291 | + await asyncio.wait_for(finalize(), self._cleanup_timeout.total_seconds()) |
| 292 | + except TimeoutError: |
| 293 | + self.log.exception('Actor cleanup timed out') |
| 294 | + finally: |
| 295 | + self._active = False |
300 | 296 |
|
301 | 297 | if reraise_control_flow: |
302 | 298 | # Return without `sys.exit()` so the original exception re-raises. |
@@ -1496,28 +1492,6 @@ def _get_remaining_time(self) -> timedelta | None: |
1496 | 1492 | ) |
1497 | 1493 | return None |
1498 | 1494 |
|
1499 | | - @contextmanager |
1500 | | - def _detach_current_listener_task(self) -> Iterator[None]: |
1501 | | - """Temporarily remove the current task from the event manager's listener-task set. |
1502 | | -
|
1503 | | - If `exit()` / `fail()` runs inside an event listener, the current task is that listener's own tracked |
1504 | | - task, so the cleanup waits below would deadlock on it and raise `RecursionError` on the timeout |
1505 | | - cancellation. Detaching it skips it in those waits; restoring it lets the listener wrapper deregister it. |
1506 | | -
|
1507 | | - Only a direct call on the listener's task is handled, not one from a task the listener itself spawns |
1508 | | - (asyncio exposes no task ancestry). |
1509 | | - """ |
1510 | | - listener_tasks = self.event_manager._listener_tasks # noqa: SLF001 |
1511 | | - current_task = asyncio.current_task() |
1512 | | - is_listener_task = current_task is not None and current_task in listener_tasks |
1513 | | - if is_listener_task: |
1514 | | - listener_tasks.discard(current_task) |
1515 | | - try: |
1516 | | - yield |
1517 | | - finally: |
1518 | | - if is_listener_task: |
1519 | | - listener_tasks.add(current_task) |
1520 | | - |
1521 | 1495 |
|
1522 | 1496 | Actor = cast('_ActorType', Proxy(_ActorType)) |
1523 | 1497 | """The entry point of the SDK, through which all the Actor operations should be done.""" |
0 commit comments