Commit ae91f05
[core][train][data] Keep strong references to fire-and-forget asyncio tasks (ray-project#63291)
## Why are these changes needed?
Python's asyncio documentation explicitly warns that the event loop only
holds **weak** references to tasks created via `asyncio.create_task` /
`loop.create_task`. A task without any other strong reference can be
garbage collected at **any** time — even before it finishes:
> Important: Save a reference to the result of this function, to avoid a
task disappearing mid-execution. The event loop only keeps weak
references to tasks. A task that isn't referenced elsewhere may be
garbage collected at any time, even before it's done.
>
> —
https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task
Three call sites in the repository were violating this contract (caught
by ruff's `RUF006` rule). All three create background tasks whose return
value is discarded, so the resulting `Task` object is only referenced by
the event loop's weak set and may be GC'd at any moment:
- **`python/ray/_private/async_utils.py`** — `enable_monitor_loop_lag()`
The event-loop lag monitor task could be silently collected, stopping
lag monitoring without warning.
-
**`python/ray/train/v2/_internal/execution/checkpoint/checkpoint_manager.py`**
— `CheckpointManager._notify()`
The notify task wakes up coroutines waiting on `self._condition`. If
it's collected before `notify_all()` runs, listeners may wait forever.
- **`python/ray/data/_internal/planner/plan_udf_map_op.py`** —
`_generate_transform_fn_for_async_map().._execute_transform()`
The `_reorder` background task is responsible for forwarding completed
results from `completed_tasks_queue` into the output queue in
deterministic order. Losing this task to GC would silently break the
entire async map operation.
## What was changed
Each of the three sites now retains a strong reference to the created
task using the pattern recommended by the asyncio docs:
| File | Pattern |
|---|---|
| `async_utils.py` | Module-level `_BACKGROUND_TASKS: Set[asyncio.Task]`
+ `task.add_done_callback(_BACKGROUND_TASKS.discard)` |
| `checkpoint_manager.py` | Per-instance `self._background_tasks: set` +
`add_done_callback(self._background_tasks.discard)` |
| `plan_udf_map_op.py` | Local variable `reorder_task =
asyncio.create_task(_reorder())`, awaited in the `finally` block of
`_execute_transform` (also propagates unexpected exceptions) |
No public API change. No behavior change in the happy path — only
correctness under GC pressure.
## Related issues
N/A (silences the `RUF006` lint warnings for these three files).
## Checks
- [x] I've signed off every commit (DCO).
- [x] `ruff check --select RUF006` passes on the three modified files.
- [x] `python -m py_compile` passes for all three files.
- [ ] I've made sure the tests are passing.
---------
Signed-off-by: forwardxu <forwardxu@apache.org>
Signed-off-by: phattruong <23120318@student.hcmus.edu.vn>1 parent 89f64d0 commit ae91f05
3 files changed
Lines changed: 33 additions & 5 deletions
File tree
- python/ray
- _private
- data/_internal/planner
- train/v2/_internal/execution/checkpoint
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
25 | 31 | | |
26 | 32 | | |
27 | 33 | | |
| |||
49 | 55 | | |
50 | 56 | | |
51 | 57 | | |
52 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
876 | 876 | | |
877 | 877 | | |
878 | 878 | | |
879 | | - | |
880 | | - | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
881 | 885 | | |
882 | 886 | | |
883 | 887 | | |
| |||
926 | 930 | | |
927 | 931 | | |
928 | 932 | | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
929 | 938 | | |
930 | 939 | | |
931 | 940 | | |
| |||
Lines changed: 11 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
127 | 132 | | |
128 | 133 | | |
129 | 134 | | |
| |||
248 | 253 | | |
249 | 254 | | |
250 | 255 | | |
251 | | - | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
252 | 262 | | |
253 | 263 | | |
254 | 264 | | |
| |||
0 commit comments