fix(cron): terminal-worker reaper lives in scheduler_detached_worker, not the scheduler facade
cron/scheduler.py is already past the facade line-count gate; the reap helper is a detached-worker teardown concern with an existing topical home. The waiter late-imports it so behaviour and the sync run_one_job contract are unchanged.
This commit is contained in:
@@ -3096,23 +3096,6 @@ def _run_one_job_body(
|
||||
reset_terminal_scope(_terminal_scope_token)
|
||||
|
||||
|
||||
def _reap_terminal_worker_in_background(process: subprocess.Popen) -> None:
|
||||
"""Keep the reap contract when the waiter returns before the worker exits.
|
||||
|
||||
The ledger turning terminal lets the waiter return while the worker is
|
||||
still in final teardown. The gateway remains the worker's parent, so if
|
||||
nobody calls ``wait()`` afterwards the worker lingers as a zombie (STAT=Z)
|
||||
under the gateway until it is restarted (#114509). A short-lived daemon
|
||||
thread holds that single responsibility and ends with the process exit
|
||||
it waits for.
|
||||
"""
|
||||
threading.Thread(
|
||||
target=process.wait,
|
||||
name=f"cron-worker-reap-{getattr(process, 'pid', '?')}",
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
|
||||
def _wait_for_external_cron_worker_body(
|
||||
process: subprocess.Popen,
|
||||
*,
|
||||
@@ -3139,7 +3122,9 @@ def _wait_for_external_cron_worker_body(
|
||||
returncode = process.wait(timeout=1.0)
|
||||
except subprocess.TimeoutExpired:
|
||||
if _is_terminal():
|
||||
_reap_terminal_worker_in_background(process)
|
||||
from cron.scheduler_detached_worker import reap_terminal_worker_in_background
|
||||
|
||||
reap_terminal_worker_in_background(process)
|
||||
return True
|
||||
continue
|
||||
# The worker can commit its terminal row and exit between the first
|
||||
|
||||
@@ -9,6 +9,8 @@ overlap behind #102827. The worker's Future owns the teardown instead.
|
||||
from __future__ import annotations
|
||||
|
||||
import concurrent.futures
|
||||
import subprocess
|
||||
import threading
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@@ -32,3 +34,20 @@ def defer_teardown_to_running_worker(
|
||||
# Runs inline if the worker finished between done() and here — still exactly once.
|
||||
future.add_done_callback(_finish)
|
||||
return True
|
||||
|
||||
|
||||
def reap_terminal_worker_in_background(process: subprocess.Popen) -> None:
|
||||
"""Keep the reap contract when the waiter returns before the worker exits.
|
||||
|
||||
The ledger turning terminal lets ``_wait_for_external_cron_worker_body``
|
||||
return while the worker is still in final teardown. The gateway remains the
|
||||
worker's parent, so if nobody calls ``wait()`` afterwards the worker lingers
|
||||
as a zombie (STAT=Z) under the gateway until it is restarted (#114509). A
|
||||
short-lived daemon thread holds that single responsibility and ends with
|
||||
the process exit it waits for.
|
||||
"""
|
||||
threading.Thread(
|
||||
target=process.wait,
|
||||
name=f"cron-worker-reap-{getattr(process, 'pid', '?')}",
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
Reference in New Issue
Block a user