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 724aaade2f6 Bump structlog>=26.1.0 and croniter>=6.2.2 to fix memory
leaks (#70694)
724aaade2f6 is described below
commit 724aaade2f6209924125a46304e036434e41caa4
Author: Jason(Zhe-You) Liu <[email protected]>
AuthorDate: Thu Jul 30 17:51:57 2026 +0800
Bump structlog>=26.1.0 and croniter>=6.2.2 to fix memory leaks (#70694)
* Bump structlog>=26.1.0 and croniter>=6.1.0 to fix memory leaks
* Raise croniter floor to 6.2.2 and drop obsolete structlog workarounds
---
airflow-core/pyproject.toml | 4 ++--
airflow-ctl/pyproject.toml | 2 +-
shared/dagnode/pyproject.toml | 2 +-
shared/listeners/pyproject.toml | 2 +-
shared/logging/pyproject.toml | 2 +-
.../src/airflow_shared/logging/structlog.py | 28 ++++------------------
shared/observability/pyproject.toml | 2 +-
shared/providers_discovery/pyproject.toml | 2 +-
task-sdk/pyproject.toml | 2 +-
uv.lock | 18 +++++++-------
10 files changed, 23 insertions(+), 41 deletions(-)
diff --git a/airflow-core/pyproject.toml b/airflow-core/pyproject.toml
index 45a73e1633d..0657e4f9231 100644
--- a/airflow-core/pyproject.toml
+++ b/airflow-core/pyproject.toml
@@ -85,7 +85,7 @@ dependencies = [
"cadwyn>=6.1.1",
"colorlog>=6.8.2",
"cron-descriptor>=1.2.24",
- "croniter>=2.0.2",
+ "croniter>=6.2.2",
# Cryptography could be upgraded to 46.0.5, but it does not have overlap
with earlier versions
# Of Airflow which were limited to <46.0.0 also earlier provider versions
will not be compatible with newer
# airflow if we do not have overlapping version. We could set minimum
version to 46.0.0 when we drop
@@ -161,7 +161,7 @@ dependencies = [
# Start of shared logging dependencies
"msgspec>=0.19.0",
"pygtrie>=2.5.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
# End of shared logging dependencies
# Start of shared configuration dependencies
"pyyaml>=6.0.3",
diff --git a/airflow-ctl/pyproject.toml b/airflow-ctl/pyproject.toml
index 170b637cf85..2b788c987e4 100644
--- a/airflow-ctl/pyproject.toml
+++ b/airflow-ctl/pyproject.toml
@@ -39,7 +39,7 @@ dependencies = [
"pydantic>=2.11.0", # https://github.com/apache/airflow/issues/56482
"pyyaml>=6.0.3",
"rich-argparse>=1.0.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
"uuid6>=2024.7.10",
"tabulate>=0.9.0",
"tenacity>=9.1.4",
diff --git a/shared/dagnode/pyproject.toml b/shared/dagnode/pyproject.toml
index 01189ccc765..e0870ea887a 100644
--- a/shared/dagnode/pyproject.toml
+++ b/shared/dagnode/pyproject.toml
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
]
[dependency-groups]
diff --git a/shared/listeners/pyproject.toml b/shared/listeners/pyproject.toml
index f798410c131..92688eb466e 100644
--- a/shared/listeners/pyproject.toml
+++ b/shared/listeners/pyproject.toml
@@ -26,7 +26,7 @@ classifiers = [
dependencies = [
"opentelemetry-api>=1.27.0",
"pluggy>=1.5.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
]
[dependency-groups]
diff --git a/shared/logging/pyproject.toml b/shared/logging/pyproject.toml
index 22c3a6541a6..99ee05dbf14 100644
--- a/shared/logging/pyproject.toml
+++ b/shared/logging/pyproject.toml
@@ -26,7 +26,7 @@ classifiers = [
dependencies = [
"msgspec>=0.19.0",
"pygtrie>=2.5.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
]
[dependency-groups]
diff --git a/shared/logging/src/airflow_shared/logging/structlog.py
b/shared/logging/src/airflow_shared/logging/structlog.py
index 1c4341e99e5..b13be191445 100644
--- a/shared/logging/src/airflow_shared/logging/structlog.py
+++ b/shared/logging/src/airflow_shared/logging/structlog.py
@@ -24,7 +24,6 @@ import logging
import os
import re
import sys
-import weakref
from collections.abc import Callable, Iterable, Mapping, Sequence
from functools import cache, cached_property
from pathlib import Path
@@ -254,25 +253,19 @@ def make_filtering_logger() -> Callable[...,
BindableLogger]:
return maker
-# structlog >= 26.1.0 added a `name` slot + kwarg to BytesLogger
-# (hynek/structlog#786). Detect it once so we can avoid a redundant slot and
-# forward `name` through the parent init. The same detection is applied to
-# WriteLogger so the analogous upstream change lands without a regression.
-_BYTES_LOGGER_HAS_NAME = "name" in getattr(structlog.BytesLogger, "__slots__",
())
+# structlog >= 26.1.0 (our floor) gave BytesLogger a `name` slot + kwarg
+# (hynek/structlog#786), but WriteLogger has not received the analogous change
+# yet. Detect it so the upstream addition lands without a regression.
_WRITE_LOGGER_HAS_NAME = "name" in getattr(structlog.WriteLogger, "__slots__",
())
class NamedBytesLogger(structlog.BytesLogger):
- __slots__ = () if _BYTES_LOGGER_HAS_NAME else ("name",)
+ __slots__ = ()
def __init__(self, name: str | None = None, file: BinaryIO | None = None):
if file is not None:
file = make_file_io_non_caching(file)
- if _BYTES_LOGGER_HAS_NAME:
- super().__init__(file, name=name) # type: ignore[call-arg]
- else:
- super().__init__(file)
- self.name = name
+ super().__init__(file, name=name)
class NamedWriteLogger(structlog.WriteLogger):
@@ -644,17 +637,6 @@ def configure_logging(
text_output = cast("TextIO", output)
logger_factory = LoggerFactory(NamedWriteLogger, io=text_output)
- # Replace structlog's WRITE_LOCKS dict with a WeakKeyDictionary so entries
- # for closed file descriptors are garbage-collected instead of leaking.
- # TODO: drop once structlog ships the upstream fix (tracked for 26.1.0).
- try:
- from structlog import _output as _structlog_output
-
- if isinstance(_structlog_output.WRITE_LOCKS, dict):
- _structlog_output.WRITE_LOCKS = weakref.WeakKeyDictionary() #
type: ignore[assignment]
- except Exception:
- pass
-
structlog.configure(
processors=shared_pre_chain + [for_structlog],
cache_logger_on_first_use=cache_logger_on_first_use,
diff --git a/shared/observability/pyproject.toml
b/shared/observability/pyproject.toml
index f75a9d369f4..ed0dae24fd1 100644
--- a/shared/observability/pyproject.toml
+++ b/shared/observability/pyproject.toml
@@ -26,7 +26,7 @@ classifiers = [
dependencies = [
"opentelemetry-api>=1.27.0",
"pendulum>=3.1.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
"methodtools>=0.4.7",
]
diff --git a/shared/providers_discovery/pyproject.toml
b/shared/providers_discovery/pyproject.toml
index 75dc5ab041e..a4aa7ba6a97 100644
--- a/shared/providers_discovery/pyproject.toml
+++ b/shared/providers_discovery/pyproject.toml
@@ -27,7 +27,7 @@ dependencies = [
"packaging>=25.0",
"pendulum>=3.1.0",
"jsonschema>=4.19.1",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
"pygtrie>=2.5.0",
"methodtools>=0.4.7",
'importlib_metadata>=6.5;python_version<"3.12"',
diff --git a/task-sdk/pyproject.toml b/task-sdk/pyproject.toml
index 34a43329247..bb8f7e2c3f4 100644
--- a/task-sdk/pyproject.toml
+++ b/task-sdk/pyproject.toml
@@ -60,7 +60,7 @@ dependencies = [
"msgspec>=0.19.0",
"python-dateutil>=2.7.0",
"psutil>=6.1.0",
- "structlog>=25.4.0",
+ "structlog>=26.1.0",
"greenback>=1.2.1",
"tenacity>=8.3.0",
# Start of shared timezones dependencies
diff --git a/uv.lock b/uv.lock
index 7120d1597ab..f8a31f62196 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2079,7 +2079,7 @@ requires-dist = [
{ name = "cadwyn", specifier = ">=6.1.1" },
{ name = "colorlog", specifier = ">=6.8.2" },
{ name = "cron-descriptor", specifier = ">=1.2.24" },
- { name = "croniter", specifier = ">=2.0.2" },
+ { name = "croniter", specifier = ">=6.2.2" },
{ name = "cryptography", specifier = ">=44.0.3" },
{ name = "deprecated", specifier = ">=1.2.13" },
{ name = "dill", specifier = ">=0.2.2" },
@@ -2133,7 +2133,7 @@ requires-dist = [
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0.50" },
{ name = "starlette", specifier = ">=1.0.1" },
{ name = "statsd", marker = "extra == 'statsd'", specifier = ">=3.3.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
{ name = "svcs", specifier = ">=25.1.0" },
{ name = "tabulate", specifier = ">=0.9.0" },
{ name = "tenacity", specifier = ">=8.3.0" },
@@ -2215,7 +2215,7 @@ requires-dist = [
{ name = "pydantic", specifier = ">=2.11.0" },
{ name = "pyyaml", specifier = ">=6.0.3" },
{ name = "rich-argparse", specifier = ">=1.0.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
{ name = "tabulate", specifier = ">=0.9.0" },
{ name = "tenacity", specifier = ">=9.1.4" },
{ name = "uuid6", specifier = ">=2024.7.10" },
@@ -8567,7 +8567,7 @@ mypy = [
]
[package.metadata]
-requires-dist = [{ name = "structlog", specifier = ">=25.4.0" }]
+requires-dist = [{ name = "structlog", specifier = ">=26.1.0" }]
[package.metadata.requires-dev]
dev = [{ name = "apache-airflow-devel-common", editable = "devel-common" }]
@@ -8597,7 +8597,7 @@ mypy = [
requires-dist = [
{ name = "opentelemetry-api", specifier = ">=1.27.0" },
{ name = "pluggy", specifier = ">=1.5.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
]
[package.metadata.requires-dev]
@@ -8630,7 +8630,7 @@ mypy = [
requires-dist = [
{ name = "msgspec", specifier = ">=0.19.0" },
{ name = "pygtrie", specifier = ">=2.5.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
]
[package.metadata.requires-dev]
@@ -8712,7 +8712,7 @@ requires-dist = [
{ name = "opentelemetry-proto", marker = "extra == 'otel'", specifier =
">=1.27.0,<9999" },
{ name = "pendulum", specifier = ">=3.1.0" },
{ name = "statsd", marker = "extra == 'statsd'", specifier = ">=3.3.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
]
provides-extras = ["otel", "statsd", "datadog", "all"]
@@ -8791,7 +8791,7 @@ requires-dist = [
{ name = "packaging", specifier = ">=25.0" },
{ name = "pendulum", specifier = ">=3.1.0" },
{ name = "pygtrie", specifier = ">=2.5.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
]
[package.metadata.requires-dev]
@@ -9053,7 +9053,7 @@ requires-dist = [
{ name = "sentry-sdk", marker = "extra == 'sentry'", specifier =
">=2.30.0" },
{ name = "statsd", marker = "extra == 'all'", specifier = ">=3.3.0" },
{ name = "statsd", marker = "extra == 'statsd'", specifier = ">=3.3.0" },
- { name = "structlog", specifier = ">=25.4.0" },
+ { name = "structlog", specifier = ">=26.1.0" },
{ name = "tenacity", specifier = ">=8.3.0" },
{ name = "typing-extensions", specifier = ">=4.14.1" },
]