From ee7e73090bfd72ab175fe7ad66341eef0dac1dcd Mon Sep 17 00:00:00 2001 From: Joe McGinley <116890464+jomcgi@users.noreply.github.com> Date: Mon, 17 Mar 2025 21:09:32 +0000 Subject: [PATCH] Fix oltp exporter shutdown race condition Exports can start after the lock is acquired but before the shutdown flag is set, this raises an error if the channel has already been closed. Avoid this race condition by setting the shutdown flag before acquiring the lock. --- CHANGELOG.md | 2 ++ .../src/opentelemetry/exporter/otlp/proto/grpc/exporter.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 489e744b8ae..b59f6321692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#4475](https://github.com/open-telemetry/opentelemetry-python/pull/4475)) - Improve performance of baggage operations ([#4466](https://github.com/open-telemetry/opentelemetry-python/pull/4466)) +- opentelemetry-exporter-otlp-proto-grpc: fix shutdown race condition + ([#4490](https://github.com/open-telemetry/opentelemetry-python/pull/4490)) ## Version 1.31.0/0.52b0 (2025-03-12) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py index 4be75c5335e..4ceeea22fb7 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py @@ -356,9 +356,10 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: if self._shutdown: logger.warning("Exporter already shutdown, ignoring call") return + # set shutdown flag to prevent new exports + self._shutdown = True # wait for the last export if any self._export_lock.acquire(timeout=timeout_millis / 1e3) - self._shutdown = True self._channel.close() self._export_lock.release()