bujjibabukatta opened a new pull request, #70635:
URL: https://github.com/apache/airflow/pull/70635

   Title
   
   fix(amazon): include deferred-task trigger logs when reading from CloudWatch 
(#70317)
   
   Body
   
   Closes #70317.
   
   Root cause
   
   CloudWatchRemoteLogIO.stream() (and the legacy 
CloudwatchTaskHandler._read_remote_logs()) only ever read the task's own 
CloudWatch stream. A deferred task's triggerer logs are written to a separate 
stream, <task log stream>.trigger.<triggerer job id>.log 
(FileTaskHandler.add_triggerer_suffix). While the task is DEFERRED, the UI 
tails those logs live from the triggerer over HTTP, which is why they're 
visible during the deferral — but once the task finishes, that live path goes 
away and nothing ever looked in the separate CloudWatch stream. The local-file 
backend doesn't have this problem because FileTaskHandler._read_from_local() 
uses glob(worker_log_path.name + "*"), which picks up attempt=1.log and 
attempt=1.log.trigger.*.log for free. CloudWatch has no glob equivalent, so the 
trigger stream has to be discovered explicitly.
   
   Fix
   Added AwsLogsHook.describe_log_streams(): a synchronous, paginated wrapper 
around DescribeLogStreams with a prefix filter (mirrors the existing async 
variant's ResourceNotFoundException → [] handling for a not-yet-existing log 
group).
   CloudWatchRemoteLogIO.stream() now looks up any <stream>.trigger.*.log 
streams via that prefix scan and reads each one the same way it reads the base 
stream, merging them into the returned log groups. Skipped while the task is 
actively DEFERRED, since the live HTTP path already covers that state and the 
extra API call would just be repeated on every UI poll for a potentially 
long-running deferral.
   Multiple trigger streams (a task deferred, resumed, and deferred again — 
even by different triggerer processes) are sorted numerically by job id, not 
lexicographically — job id 7 must sort before job id 200. (Caught this via test 
— an initial plain-string sort got it backwards.)
   Applied the identical fix to the legacy 
CloudwatchTaskHandler._read_remote_logs() path (still registered in 
provider.yaml for older-style log-handler configs). Also removed a pre-existing 
dead call there (self.io.read(...), whose result was immediately discarded and 
redone manually right below it — wasting a CloudWatch API call on every read).
   Trigger-stream discovery failures (e.g. a permissions issue) are reported as 
an extra message rather than raising, consistent with the existing error 
handling on the base stream.
   Backward compatibility
   
   When no trigger streams exist (the common, non-deferred case), behavior and 
API call count are unchanged — verified via test that the discovery call only 
fires when needed and returns [] cleanly for a non-existent/empty-prefix case.
   
   Testing
   12 new tests added to test_cloudwatch_task_handler.py, covering: 
base+trigger merge, correct numeric ordering across multiple trigger streams, 
the DEFERRED-state skip, graceful handling of a DescribeLogStreams failure, the 
legacy handler path, correct colon-replacement in the discovery prefix, and 
hook-level pagination (tested with 54+ streams) and missing-log-group handling.
   All 42 tests in the file pass (33 existing + 12 new — some existing tests 
exercise overlapping paths).
   ruff check, ruff format --check, and mypy all pass clean on the three 
changed files.
   Trade-off worth flagging for reviewers
   
   This adds one DescribeLogStreams API call per log read for tasks that are 
not currently DEFERRED (previously: zero). For a task that was never deferred, 
this returns an empty list almost instantly, but it is still an extra 
round-trip. Happy to gate this further (e.g. only when try_number matches a 
TaskInstanceHistory row known to have gone through DEFERRED) if that trade-off 
is a concern — went with the simpler, always-check approach first since it's 
the correct and easy default and mirrors what the issue reporter's own tested 
workaround did.
   
   AI Disclosure
    This contribution used AI assistance.
   Model(s) used: Claude
   
   AI was used for:
   
   Helping write this PR description.
   Running the test suite locally to make sure everything passes before 
submitting.
   Reviewing the implementation from a performance perspective.
   The implementation and code changes were developed and validated by me.


-- 
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