Skip to content

Commit 69e2b80

Browse files
committed
Clean up a Lang-SDK runtime parse whose start fails after the fork
Only the fork itself was guarded. A failure while registering the listeners or sending the start request left the child waiting for that request and both listeners open, and the standalone run does not guard start() either.
1 parent b4025a2 commit 69e2b80

2 files changed

Lines changed: 39 additions & 16 deletions

File tree

‎airflow-core/src/airflow/dag_processing/task_handler_processor.py‎

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,23 +253,28 @@ def start( # type: ignore[override]
253253
for listener in listeners.values():
254254
listener.close()
255255
raise
256-
for channel, listener in listeners.items():
257-
proc._open_sockets[listener] = f"{channel}-listener"
258-
proc.selector.register(
259-
listener,
260-
selectors.EVENT_READ,
261-
(functools.partial(proc._accept_connection, channel=channel), proc._on_socket_closed),
256+
try:
257+
for channel, listener in listeners.items():
258+
proc._open_sockets[listener] = f"{channel}-listener"
259+
proc.selector.register(
260+
listener,
261+
selectors.EVENT_READ,
262+
(functools.partial(proc._accept_connection, channel=channel), proc._on_socket_closed),
263+
)
264+
proc.send_msg(
265+
StartTaskHandlerRuntime(
266+
file=parse_request.file,
267+
bundle_path=bundle_path,
268+
coordinator=coordinator,
269+
comm_address=listeners["comm"].getsockname()[:2],
270+
logs_address=listeners["logs"].getsockname()[:2],
271+
),
272+
request_id=0,
262273
)
263-
proc.send_msg(
264-
StartTaskHandlerRuntime(
265-
file=parse_request.file,
266-
bundle_path=bundle_path,
267-
coordinator=coordinator,
268-
comm_address=listeners["comm"].getsockname()[:2],
269-
logs_address=listeners["logs"].getsockname()[:2],
270-
),
271-
request_id=0,
272-
)
274+
except BaseException:
275+
proc._kill_runtime()
276+
proc.close()
277+
raise
273278
return proc
274279

275280
@classmethod

‎airflow-core/tests/unit/dag_processing/test_task_handler_processor.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,24 @@ def test_a_connection_is_used_once_it_is_verified(self, mock_parse_task_handler,
250250

251251
assert _get_task_ids(proc.parsing_result) == ["extract"]
252252

253+
@patch.object(
254+
LangSDKTaskHandlerProcessorProcess,
255+
"send_msg",
256+
autospec=True,
257+
side_effect=OSError("cannot send the start request"),
258+
)
259+
def test_a_start_that_fails_after_the_fork_leaves_nothing_behind(self, mock_send_msg, tmp_path):
260+
fds_before = _get_open_fds()
261+
children_before = {child.pid for child in psutil.Process().children()}
262+
263+
with selectors.DefaultSelector() as selector:
264+
with pytest.raises(OSError, match="cannot send the start request"):
265+
_start(tmp_path, selector)
266+
assert selector.get_map() == {}
267+
268+
assert {child.pid for child in psutil.Process().children()} == children_before
269+
assert _get_open_fds() <= fds_before
270+
253271
@patch.object(BaseDagFileProcessorProcess, "start", autospec=True, side_effect=OSError("fork failed"))
254272
def test_a_start_that_fails_before_the_fork_closes_its_listeners(self, mock_start, tmp_path):
255273
fds_before = _get_open_fds()

0 commit comments

Comments
 (0)