Skip to content

fix: gRPC RST_STREAM on event ingestion — logging interceptor, auth i…#82

Merged
SteakFisher merged 1 commit into
mainfrom
fix/grpc-rst-stream
Jun 6, 2026
Merged

fix: gRPC RST_STREAM on event ingestion — logging interceptor, auth i…#82
SteakFisher merged 1 commit into
mainfrom
fix/grpc-rst-stream

Conversation

@SteakFisher

Copy link
Copy Markdown
Member

…nterceptor, envoy config

@greptile-apps

greptile-apps Bot commented Jun 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR addresses gRPC RST_STREAM errors during event ingestion by fixing three complementary layers: the logging interceptor's async error path now calls originalCallback directly (bypassing wrappedCallback's logging side-effects), the auth interceptor's non-cached catch blocks now emit proper { code, details } gRPC status objects, and Envoy gains explicit timeout: 60s / max_stream_duration: 300s settings.

  • logging.ts: Replaces throw error in the .catch handler with a direct originalCallback call, eliminating the double-Sentry-capture and double wide-event emission that occurred when wrappedCallback had already run.
  • auth.ts: Two catch blocks now return structured { code: grpcStatus.UNAVAILABLE, details } objects instead of raw errors; the equivalent catch in the cached path (line 186) was not updated and still forwards a raw error.
  • envoy.yaml: Adds route-level timeouts — timeout: 60s for both backends and max_stream_duration: 300s specifically for the gRPC route's client-streaming calls.

Confidence Score: 4/5

Safe to merge with one known gap: the cached-path catch in auth.ts (line 186) still forwards raw errors, so any DB failure on a repeated request for a cached key hits exactly the same RST_STREAM condition this PR was written to cure.

The core fixes in logging.ts and the non-cached auth path are correct and well-scoped. The remaining unpatched catch in the cached auth path is a real gap — after the first successful lookup, all subsequent requests for the same key go through that path, meaning a transient DB error there still produces a raw error with no gRPC code.

src/interceptors/auth.ts — the cached-path webhook check catch at line 186 was not updated alongside the two catches that were fixed.

Important Files Changed

Filename Overview
src/interceptors/auth.ts Fixes two of the three catch blocks to emit proper gRPC status objects; the cached-path catch at line 186 is still passing the raw error. New plain-object shape { code, details } passed to the gRPC callback degrades wide-event logging for DB errors (message logged as "[object Object]").
src/interceptors/logging.ts Replaces throw error with a direct originalCallback call in the async .catch handler, correctly breaking the double-capture cycle and ensuring proper gRPC error propagation without re-invoking wrappedCallback's logging side-effects.
envoy/envoy.yaml Adds timeout: 60s on both routes and max_stream_duration: 300s on the gRPC route. For the client-streaming StreamEvents RPC, the route timeout only fires after the client ends the stream, so max_stream_duration: 300s is what caps total stream lifetime — the combination looks correct.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Envoy
    participant loggingInterceptor
    participant authInterceptor
    participant Handler

    Client->>Envoy: gRPC request (timeout: 60s / max_stream_duration: 300s)
    Envoy->>loggingInterceptor: forward request
    loggingInterceptor->>loggingInterceptor: wrap callback → wrappedCallback
    loggingInterceptor->>authInterceptor: handler(call, wrappedCallback)
    authInterceptor->>authInterceptor: validate API key (cache hit or DB lookup)

    alt DB error in non-cached path
        authInterceptor-->>loggingInterceptor: "callback({code: UNAVAILABLE, details})"
        loggingInterceptor->>loggingInterceptor: extractErrorDetails → plain obj → [object Object]
        loggingInterceptor->>loggingInterceptor: Sentry.captureException + builder.setError(500)
        loggingInterceptor-->>Client: UNAVAILABLE (gRPC code correct, log wrong)
    else async handler throws
        authInterceptor-->>loggingInterceptor: Promise rejects
        loggingInterceptor->>loggingInterceptor: .catch → extractErrorDetails
        alt outcome not yet set
            loggingInterceptor->>loggingInterceptor: captureException + setError + logger.emit
        end
        loggingInterceptor-->>Client: "originalCallback({code, details}) no double-capture"
    else success
        authInterceptor->>Handler: handler(call, wrappedCallback)
        Handler-->>loggingInterceptor: wrappedCallback(null, response)
        loggingInterceptor->>loggingInterceptor: builder.setSuccess(200) + logger.emit
        loggingInterceptor-->>Client: response
    end
Loading

Reviews (2): Last reviewed commit: "fix: gRPC RST_STREAM on event ingestion ..." | Re-trigger Greptile

Comment thread src/interceptors/logging.ts
@SteakFisher SteakFisher force-pushed the fix/grpc-rst-stream branch from b64a5d7 to 016f587 Compare June 6, 2026 18:24
@SteakFisher SteakFisher merged commit 94f98a0 into main Jun 6, 2026
2 checks passed
@SteakFisher SteakFisher deleted the fix/grpc-rst-stream branch June 6, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant