ferruzzi commented on code in PR #68779:
URL: https://github.com/apache/airflow/pull/68779#discussion_r3455112840


##########
providers/amazon/src/airflow/providers/amazon/aws/log/cloudwatch_task_handler.py:
##########
@@ -118,6 +121,17 @@ def handler(self) -> watchtower.CloudWatchLogHandler:
             json_serialize_default=_json_serialize or json_serialize_legacy,
         )
 
+    @property
+    def handler(self) -> watchtower.CloudWatchLogHandler:
+        """Return the streaming handler, rebuilding it if dictConfig closed it 
mid-task."""
+        # dictConfig's non-incremental reset closes every handler in 
logging._handlerList,
+        # leaving this one with shutting_down=True (it then silently drops 
every record).
+        # Rebuild only while the IO is live: once close() has run, keep the 
closed handler so a
+        # late record is dropped instead of spawning an orphan handler + 
background thread.

Review Comment:
   Nit:   Can you merge this into a proper docsting instead of a docstring and 
several inlines?



##########
providers/amazon/src/airflow/providers/amazon/aws/log/cloudwatch_task_handler.py:
##########
@@ -127,16 +141,19 @@ def processors(self) -> tuple[structlog.typing.Processor, 
...]:
         logRecordFactory = getLogRecordFactory()
         # The handler MUST be initted here, before the processor is actually 
used to log anything.
         # Otherwise, logging that occurs during the creation of the handler 
can create infinite loops.
-        _handler = self.handler
+        _ = self.handler
         from airflow.sdk.log import relative_path_from_logger
 
         def proc(logger: structlog.typing.WrappedLogger, method_name: str, 
event: structlog.typing.EventDict):
             if not logger or not (stream_name := 
relative_path_from_logger(logger)):
                 return event
+            # Resolve the handler on every record: configure_logging() may have
+            # closed the one built above, in which case ``handler`` rebuilds 
it.
+            handler = self.handler

Review Comment:
   I wonder if this is necessary instead of using `self.handler` inline below, 
but maybe it avoids a race condition?  I guess it's trivial to keep it.



##########
providers/amazon/src/airflow/providers/amazon/aws/log/cloudwatch_task_handler.py:
##########
@@ -151,20 +168,21 @@ def proc(logger: structlog.typing.WrappedLogger, 
method_name: str, event: struct
                 ct = created.timestamp()
                 record.created = ct
                 record.msecs = int((ct - int(ct)) * 1000) + 0.0  # Copied from 
stdlib logging
-            _handler.handle(record)
+            handler.handle(record)
             return event
 
         return (proc,)
 
     def close(self):
-        # Use the flush method to ensure all logs are sent to CloudWatch.
-        # Closing the handler sets `shutting_down` to True, which prevents any 
further logs from being sent.
-        # When `shutting_down` is True, means the logging system is in the 
process of shutting down,
-        # during which it attempts to flush the logs which are queued.
-        if self.handler is None or self.handler.shutting_down:
+        # Terminal flush — only ever called from upload(). Mark the IO closed 
first so `handler`
+        # stops rebuilding: a record arriving after teardown must be dropped, 
not revive a fresh
+        # handler. Read the cached handler directly so we never build one just 
to flush it.

Review Comment:
   Similar nit to above; I see it was already done this way before, but can you 
make this a proper docstring?  It will have to start with an imperative to pass 
CI, so maybe move the last sentence up to be the first line.



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