shivaam opened a new pull request, #76103: URL: https://github.com/apache/airflow/pull/76103
* related: #74717 * related: #75394 * related: #75387 A TypeScript task gets no signal at its `execution_timeout`. The runtime has no timer, so the task runs until the supervisor's backstop sends SIGTERM `killed_task_cleanup_time` (60 s) later. If the handler then returns normally, the task is recorded as **success** and its retries are skipped. The TypeScript runtime now handles the timeout itself, as the Python task runner does with SIGALRM: - It reads `execution_timeout` from the run context. Unset or `0` means no timeout, as for a Python task. A negative value has already passed, so the handler does not run. - Right before the handler (or operator) runs, it sends `StartExecutionTimeout`, so the supervisor's backstop counts from the same moment. - At the timeout it aborts `getContext().signal` with a new exported `TaskTimeoutError` as its `reason`. It then waits up to 30 s (`ABORT_GRACE_PERIOD_MS`) for the handler to clean up, or less if the supervisor's SIGTERM comes first. Then it fails the task with `Task timed out after N seconds`, as `RetryTask` if it has retries left. What the handler returns after the timeout is ignored, so a timed-out task can no longer succeed. - A handler stuck in a synchronous loop cannot see the signal; the supervisor's backstop still stops it, unchanged. | With `execution_timeout=2`, `retries=1` | Before | After | |---|---|---| | Handler passes the signal to its work | stopped at 62 s; reason "The operation was aborted" | stopped at 2 s (+ its cleanup); reason "Task timed out after 2 seconds" | | Handler returns after being aborted | **success** at 62 s, no retry | up_for_retry at 2 s | | Handler ignores the signal | killed at 92 s, no reason | timeout reported at 32 s with its reason | | Synchronous loop | SIGKILL by the supervisor | unchanged | Those rows are from running a bundle built from this branch, and one built from `main`, under the real Python supervisor (`_PopenActivitySubprocess`, real sockets and signals; only the Execution API was mocked). When #75387 merges, `StartExecutionTimeout` becomes `SetExecutionTimeout(timeout_seconds)`; the runtime then sends its own value, as #75387 asks of each SDK. Falling back to the worker's `default_task_execution_timeout` needs the coordinator to pass it to the runtime, which #75387 lists as a follow-up; until then the run context still carries the Dag processor's default, as today. Validation: - Full TS suite: 976 tests passed, including 9 new unit cases and 11 new runtime cases against the simulated supervisor. - Typecheck, ESLint, Prettier, build and `verify:package` passed; prek hooks passed on commit. - 14 cases (7 handlers × branch/`main`) under the real Python supervisor. - Full Airflow run (api-server, scheduler with LocalExecutor, Dag processor, `NodeCoordinator`, SQLite): one TypeScript Dag packed with `airflow-ts-pack` against this branch and against `main`. On `main`, the task that returns after the abort ends **success** with its retry skipped; with this change both tries fail with "Task timed out after 3 seconds". A handler that passes the signal stops at the timeout instead of at the supervisor's SIGTERM, and a synchronous loop is still killed by the supervisor. --- ##### Was generative AI tooling used to co-author this PR? - [X] Yes — Claude Code (Opus 5.5) Generated-by: Claude Code (Opus 5.5) following [the guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
