Skip to content

Commit bd0fc70

Browse files
authored
fix(grpc): Read method from handler_call_details for grpcio >= 1.76 compat (#5521)
## Summary Fixes sync `ServerInterceptor` to work with grpcio >= 1.76 by reading the method name from `handler_call_details.method` instead of `context._rpc_event.call_details.method`. ### Problem grpcio 1.76 introduced **registered method handlers** (`add_registered_method_handlers`) which resolve RPC methods at the C-core level. For these registered methods, `context._rpc_event.call_details.method` returns an empty string, causing Sentry tracing to silently fail (no transactions, no spans, no trace IDs in logs). ### Solution Capture `handler_call_details.method` directly in the closure scope before defining the `behavior` function. This approach: 1. **Fixes grpcio >= 1.76 compatibility** - `handler_call_details.method` is always populated by grpcio's `_find_method_handler` 2. **Avoids race conditions** - No shared instance state; each call creates its own closure with captured values 3. **Maintains backward compatibility** - Custom `find_name` parameter still works ### Why Closure Capture Instead of Instance State? The gRPC sync server uses a `ThreadPoolExecutor` where multiple threads share the same `ServerInterceptor` instance. Storing state as `self._handler_call_details` would create a race condition where one thread could overwrite the value before another thread's `behavior` closure reads it. Fixes #5520
1 parent 594dce5 commit bd0fc70

File tree

1 file changed

+5
-6
lines changed

1 file changed

+5
-6
lines changed

sentry_sdk/integrations/grpc/server.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def __init__(
2222
self: "ServerInterceptor",
2323
find_name: "Optional[Callable[[ServicerContext], str]]" = None,
2424
) -> None:
25-
self._find_method_name = find_name or ServerInterceptor._find_name
25+
self._custom_find_name = find_name
2626

2727
super().__init__()
2828

@@ -35,9 +35,12 @@ def intercept_service(
3535
if not handler or not handler.unary_unary:
3636
return handler
3737

38+
method_name = handler_call_details.method
39+
custom_find_name = self._custom_find_name
40+
3841
def behavior(request: "Message", context: "ServicerContext") -> "Message":
3942
with sentry_sdk.isolation_scope():
40-
name = self._find_method_name(context)
43+
name = custom_find_name(context) if custom_find_name else method_name
4144

4245
if name:
4346
metadata = dict(context.invocation_metadata())
@@ -63,7 +66,3 @@ def behavior(request: "Message", context: "ServicerContext") -> "Message":
6366
request_deserializer=handler.request_deserializer,
6467
response_serializer=handler.response_serializer,
6568
)
66-
67-
@staticmethod
68-
def _find_name(context: "ServicerContext") -> str:
69-
return context._rpc_event.call_details.method.decode()

0 commit comments

Comments
 (0)