This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new efd28053bed Stop Google Cloud Logging handler from starting a thread
on close (#75596)
efd28053bed is described below
commit efd28053bed43529dfc2ee88d24223e889e1f8c2
Author: Shahar Epstein <[email protected]>
AuthorDate: Tue Oct 27 19:42:50 2026 +0200
Stop Google Cloud Logging handler from starting a thread on close (#75596)
Closing a CloudLoggingTaskHandler that never emitted a record built a new
BackgroundThreadTransport just to flush it, starting a worker thread from
inside logging.shutdown() while dictConfig held the logging lock. Every
logging reconfiguration leaked one such thread per handler, and in the
Airflow 2.11.1 compat job the thread start blocked until
test_should_use_configured_log_name hit its 60s timeout.
Claude-Session: https://claude.ai/code/session_01RXok8FK5hAFPosJuVqdXaE
---
.../google/cloud/log/cloud_logging_task_handler.py | 8 +++++++-
.../google/cloud/log/test_cloud_logging_task_handler.py | 14 ++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git
a/providers/google/src/airflow/providers/google/cloud/log/cloud_logging_task_handler.py
b/providers/google/src/airflow/providers/google/cloud/log/cloud_logging_task_handler.py
index 536ee7189b6..a198736cb32 100644
---
a/providers/google/src/airflow/providers/google/cloud/log/cloud_logging_task_handler.py
+++
b/providers/google/src/airflow/providers/google/cloud/log/cloud_logging_task_handler.py
@@ -621,7 +621,13 @@ class CloudLoggingTaskHandler(logging.Handler):
# from ``Handler.close()`` gracefully). Print to stderr as last resort
since
# logging itself may be shutting down.
try:
- self.io.transport.flush()
+ # Read the attrs (>=23.2) cached_property slot directly so close()
never builds a
+ # transport (and starts its worker thread) during logging.shutdown.
+ try:
+ transport = object.__getattribute__(self.io, "transport")
+ except AttributeError:
+ return
+ transport.flush()
except Exception as exc:
print(
f"CloudLoggingTaskHandler.close: transport flush failed:
{type(exc).__name__}: {exc}",
diff --git
a/providers/google/tests/unit/google/cloud/log/test_cloud_logging_task_handler.py
b/providers/google/tests/unit/google/cloud/log/test_cloud_logging_task_handler.py
index 4ce4ed23832..9b83fd85348 100644
---
a/providers/google/tests/unit/google/cloud/log/test_cloud_logging_task_handler.py
+++
b/providers/google/tests/unit/google/cloud/log/test_cloud_logging_task_handler.py
@@ -28,6 +28,7 @@ from urllib.parse import parse_qs, urlsplit
import pytest
from google.cloud.logging import Resource
+from google.cloud.logging.handlers.transports import BackgroundThreadTransport
from google.cloud.logging_v2.types import ListLogEntriesRequest,
ListLogEntriesResponse, LogEntry
from airflow.exceptions import AirflowProviderDeprecationWarning
@@ -1212,6 +1213,19 @@ class TestCloudLoggingTaskHandlerExceptionHandling:
assert "[email protected]" not in message
assert "logging.logEntries.list" not in message
+ @mock.patch(
+
"airflow.providers.google.cloud.log.cloud_logging_task_handler.get_credentials_and_project_id"
+ )
+
@mock.patch("airflow.providers.google.cloud.log.cloud_logging_task_handler.gcp_logging.Client")
+ def test_close_does_not_build_unused_transport(self, mock_client,
mock_get_creds_and_project_id):
+ mock_get_creds_and_project_id.return_value = ("creds", "project_id")
+ transport_cls = mock.create_autospec(BackgroundThreadTransport)
+ handler = CloudLoggingTaskHandler(transport=transport_cls)
+
+ handler.close()
+
+ transport_cls.assert_not_called()
+
def test_close_swallows_transport_flush_errors(self, capsys):
"""``close()`` must never raise — even when transport ``flush()``
fails."""
handler = CloudLoggingTaskHandler()