From 1ca90d51c8a840f8c5cf0332a844ded3d990f053 Mon Sep 17 00:00:00 2001 From: Brett Langdon Date: Mon, 6 May 2024 05:35:15 -0400 Subject: [PATCH] fix(grpc): resolve issue with incorrect gRPC response being returned (#9157) The usage of the core API was not correct in the gRPC integration. It was working on accident based on how the listener was written. Since the listener mutates the underlying response class and not the response instance, there is nothing that needs to be returned, so we can change the `dispatch_with_results` to `dispatch`. As well, the previous usage of the `dispatch_with_results` API was not correct, the response was always replaced with the result from the ASM listener even when the response was `None`. ## Changelog No changelog entry is added since this is a fix for an unreleased change so it is not yet a "bug". ## Checklist - [x] Change(s) are motivated and described in the PR description - [x] Testing strategy is described if automated tests are not included in the PR - [x] Risks are described (performance impact, potential for breakage, maintainability) - [x] Change is maintainable (easy to change, telemetry, documentation) - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) are followed or label `changelog/no-changelog` is set - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)) - [x] Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) - [x] If this PR changes the public interface, I've notified `@DataDog/apm-tees`. ## Reviewer Checklist - [x] Title is accurate - [x] All changes are related to the pull request's stated goal - [x] Description motivates each change - [x] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - [x] Testing strategy adequately addresses listed risks - [x] Change is maintainable (easy to change, telemetry, documentation) - [x] Release note makes sense to a user of the library - [x] Author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - [x] Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) --- ddtrace/appsec/_handlers.py | 3 +-- ddtrace/contrib/grpc/client_interceptor.py | 18 ++---------------- ddtrace/internal/core/event_hub.py | 4 ++-- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/ddtrace/appsec/_handlers.py b/ddtrace/appsec/_handlers.py index e3e147b3bce..e5326f54165 100644 --- a/ddtrace/appsec/_handlers.py +++ b/ddtrace/appsec/_handlers.py @@ -410,7 +410,6 @@ def _on_grpc_response(response): msg_cls = type(response) _patch_protobuf_class(msg_cls) - return response def listen(): @@ -425,4 +424,4 @@ def listen(): core.on("flask.patch", _on_flask_patch) core.on("asgi.request.parse.body", _on_asgi_request_parse_body, "await_receive_and_body") -core.on("grpc.response_message", _on_grpc_response, "response") +core.on("grpc.response_message", _on_grpc_response) diff --git a/ddtrace/contrib/grpc/client_interceptor.py b/ddtrace/contrib/grpc/client_interceptor.py index 57808b81788..40a4f2bcbd8 100644 --- a/ddtrace/contrib/grpc/client_interceptor.py +++ b/ddtrace/contrib/grpc/client_interceptor.py @@ -81,14 +81,7 @@ def _handle_response(span, response): # google-api-core which has its own future base class # https://github.com/googleapis/python-api-core/blob/49c6755a21215bbb457b60db91bab098185b77da/google/api_core/future/base.py#L23 if hasattr(response, "_response"): - result = core.dispatch_with_results( - "grpc.response_message", - (response._response,), - ) - if result: - response_value = result.get("response") - if response_value: - response._response = response_value + core.dispatch("grpc.response_message", (response._response,)) if hasattr(response, "add_done_callback"): response.add_done_callback(_future_done_callback(span)) @@ -171,14 +164,7 @@ def _next(self): def __next__(self): n = self._next() if n is not None: - result = core.dispatch_with_results( - "grpc.response_message", - (n,), - ) - if result: - response_value = result.get("response") - if response_value: - n = response_value + core.dispatch("grpc.response_message", (n,)) return n next = __next__ diff --git a/ddtrace/internal/core/event_hub.py b/ddtrace/internal/core/event_hub.py index 5da8677b1a0..a27bde3549d 100644 --- a/ddtrace/internal/core/event_hub.py +++ b/ddtrace/internal/core/event_hub.py @@ -35,10 +35,10 @@ def __bool__(self): class EventResultDict(Dict[str, EventResult]): - def __missing__(self, key: str): + def __missing__(self, key: str) -> EventResult: return _MissingEvent - def __getattr__(self, name: str): + def __getattr__(self, name: str) -> EventResult: return dict.__getitem__(self, name)