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]

Reply via email to