Skip to content

feat(http-invocation): classify client disconnects as HTTP 499 (#524) - #563

Open
shobham-nv wants to merge 2 commits into
mainfrom
fix/is-499-client-disconnect-classification
Open

feat(http-invocation): classify client disconnects as HTTP 499 (#524)#563
shobham-nv wants to merge 2 commits into
mainfrom
fix/is-499-client-disconnect-classification

Conversation

@shobham-nv

@shobham-nv shobham-nv commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Client disconnects after dispatch were accounted as a generic 502 by the vanity gateway (the request future is dropped before any status is produced), making caller cancellations indistinguishable from genuine upstream faults and inflating 5xx / endpoint-unavailability metrics. This classifies confirmed client disconnects as HTTP 499 for internal telemetry — authoritatively in the invocation service and, where technically possible, in gateway request accounting — while leaving real upstream failures as 502. 499 is telemetry-only; the disconnected client never receives it.

Additional Details

Problem. When a client goes away after an invocation is dispatched, pexec never returns a Response. The gateway's reverse-proxy error handler mapped the resulting transport error to a single generic 502 with a fixed body, so client cancellations and genuine upstream faults collapsed into one status — no 499 anywhere, and 502 root-cause was unreliable.

Invocation service (authoritative signal). InflightRequestGuard now records whether a status was produced:

  • The handle_streaming_response(...) call site was changed from ? to a match; on the Err path it marks status_returned before returning, so a server-side early exit is not mistaken for a disconnect.
  • On Drop when the request did not complete and no status was produced (pure client disconnect), it logs request/function/org context and records app.invocation.error{http_status_code="499"}.
  • Server-side errors keep their real status, already counted via AppError::into_response — so no double counting.
  • The 499 series is pre-initialized to 0 at startup so dashboards show it before the first disconnect.

Vanity gateway (accounting). The reverse-proxy error handler reclassifies to 499 only when the inbound request context is canceled (the authoritative "client gone" signal). A transport error that merely wraps context.Canceled while the inbound context is still live stays a genuine upstream fault (502). otelhttp records whatever status is written, so the 499 lands in http_server_request_duration_seconds_count. For a mid-stream SSE disconnect the 200 is already flushed, so it remains 200 — that's the "where technically possible" limit.

Scope / limitations. The classification applies to all routes on the shared pexec path (/pexec, /exec, TLB). Existing 400 (body-read failure) handling is untouched, since that occurs before the guard exists. A true disconnect produces no IS response for that request, so the gateway detects it independently via the canceled inbound context rather than a propagated signal.

For the Reviewer

Closest files to review:

  • src/invocation-plane-services/http-invocation/crates/server/src/routes/post_pexec.rs — the InflightRequestGuard status_returned logic and the ?match change.
  • src/invocation-plane-services/vanity-gateway/gateway/vanity_director.goclientClosedRequest / writeProxyError and the inbound-context check.

Question for reviewers: comfortable keying the gateway classification off request.Context().Err() == context.Canceled as the confirmed-disconnect signal (vs. inspecting the transport error)?

For QA

Verified locally:

  • IS: cargo check --tests, cargo clippy --tests, cargo fmt --check clean; cargo test --lib — 75 pass, 4 docker-gated ignored. New tests: 499 recorded on client disconnect, not recorded on server error; existing 504 gateway-timeout test still passes.
  • Gateway: go build, go vet, gofmt clean; go test ./gateway/... passes. New tests: client disconnect (canceled context) → 499, genuine transport failure → 502; existing context.Canceled-with-live-context test still returns 502.

QA needed: light — recommend confirming in a staging/prod dashboard that app.invocation.error{http_status_code="499"} and the gateway 499 count appear on real client disconnects and that 502 drops correspondingly.

Issues

Closes #524

Checklist

  • I am familiar with the Contributing Guidelines.
  • I have signed off my commits for Developer Certificate of Origin (DCO) compliance.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Summary by CodeRabbit

  • Bug Fixes
    • Client disconnects are now reported with HTTP 499 instead of being confused with server or proxy failures.
    • Genuine upstream proxy failures continue to return HTTP 502.
    • Request metrics now include an initial zero-valued 499 series for clearer monitoring.
    • Prevented server-side errors from being incorrectly recorded as client disconnects.

@shobham-nv
shobham-nv requested a review from a team as a code owner July 30, 2026 05:18
@shobham-nv
shobham-nv requested a review from shelleyshen-0 July 30, 2026 05:18
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change classifies confirmed client disconnects as HTTP 499 in invocation metrics and vanity-gateway proxy responses. It preserves server-generated statuses and genuine upstream failures as 502.

Changes

Client disconnect classification

Layer / File(s) Summary
Invocation guard and 499 telemetry
src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs, src/invocation-plane-services/http-invocation/crates/server/src/routes/post_pexec.rs
InflightRequestGuard tracks returned status state and records 499 metrics for unfinished requests without a server status. Tests cover cancellation, completion, and server-side status handling.
Gateway proxy error mapping
src/invocation-plane-services/vanity-gateway/gateway/vanity_director.go, src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go
Canceled request contexts produce 499 Problem Details responses. Genuine upstream transport failures retain 502 responses. Tests verify response status, logs, and telemetry metrics.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant VanityGateway
  participant HttpInvocationServer
  participant InflightRequestGuard
  participant InvocationMetrics
  Client->>VanityGateway: send execution request
  VanityGateway->>HttpInvocationServer: proxy execution request
  HttpInvocationServer->>InflightRequestGuard: track in-flight invocation
  Client-->>VanityGateway: cancel request context
  InflightRequestGuard->>InvocationMetrics: record HTTP 499 without returned status
  HttpInvocationServer-->>VanityGateway: proxy error
  VanityGateway-->>Client: return 499 for canceled context
  VanityGateway-->>Client: return 502 for genuine proxy failure
Loading

Suggested reviewers: shelleyshen-0

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits and accurately describes the HTTP 499 client-disconnect classification change.
Linked Issues check ✅ Passed The changes implement HTTP 499 classification, preserve server and proxy statuses, pre-initialize metrics, and add targeted tests for issue #524.
Out of Scope Changes check ✅ Passed All modified files support client-disconnect classification, telemetry, error handling, or related tests for issue #524.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/is-499-client-disconnect-classification

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Comment @coderabbitai help to get the list of available commands.

When a client disconnects after an invocation is dispatched, the request
future is dropped before any status is produced, so the vanity gateway
accounted it as a generic 502 - indistinguishable from genuine upstream
faults and inflating 5xx/endpoint-unavailability metrics.

Invocation service (authoritative): InflightRequestGuard now tracks whether
a status was returned. On Drop with no status (client disconnect) it logs
request/function/org context and records app.invocation.error with
http_status_code=499; server-side errors keep their real status (already
counted via AppError::into_response). Pre-initialize the 499 series so it
reports 0 before the first disconnect.

Vanity gateway (accounting): reverse-proxy errors are reclassified to 499
only when the inbound request context is canceled (confirmed disconnect);
genuine upstream transport failures remain 502.

Covers all routes on the shared pexec path (/pexec, /exec, TLB). Adds tests
for client disconnect, server error, gateway timeout, and genuine proxy
failure.
@shobham-nv
shobham-nv force-pushed the fix/is-499-client-disconnect-classification branch from 9ffbbd6 to da503e7 Compare July 30, 2026 05:20
@github-actions

Copy link
Copy Markdown
Contributor

🛡️ CodeQL Analysis

🚨 Found 2 issue(s)

Severity Breakdown:

  • 🔴 Errors: 0
  • 🟡 Warnings: 0
  • 🔵 Notes: 0
📋 Top Issues

🔗 View full details in Security tab

🕐 Last updated: 2026-07-30 05:23:04 UTC | Commit: da503e7

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/invocation-plane-services/vanity-gateway/gateway/vanity_director.go (1)

83-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add request/function context to the new disconnect log, and mark span errors on proxy failure.

The new zap.L().Warn("client closed request before upstream response", zap.Error(err)) doesn't include target.FunctionID/target.FunctionVersionID, even though ServeExec already has them and puts them on the span just above. Also, neither branch of writeProxyError marks the active span as failed (no error attribute/status), so cross-service traces for both 499 and 502 outcomes won't show the failure.

As per path instructions, "Ensure every log line includes available context fields: Request ID, Function ID, Cluster ID, and Org/NCA ID." As per coding guidelines, "set error attributes on failures" is required for cross-service paths.

♻️ Proposed direction (signature change needed to thread function IDs through)
-func writeProxyError(writer http.ResponseWriter, request *http.Request, err error) {
+func writeProxyError(writer http.ResponseWriter, request *http.Request, err error, functionID, functionVersionID string) {
 	if clientClosedRequest(request) {
-		zap.L().Warn("client closed request before upstream response", zap.Error(err))
+		zap.L().Warn("client closed request before upstream response",
+			zap.Error(err), zap.String("function_id", functionID), zap.String("function_version_id", functionVersionID))
+		span := trace.SpanFromContext(request.Context())
+		span.SetAttributes(attribute.Bool("error", true))
 		writer.Header().Set("Content-Type", "application/problem+json")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/invocation-plane-services/vanity-gateway/gateway/vanity_director.go`
around lines 83 - 106, Update writeProxyError and its ServeExec call site to
thread target.FunctionID and target.FunctionVersionID into the disconnect path.
Include all available request context fields—Request ID, Function ID, Cluster
ID, and Org/NCA ID—in the client-disconnect warning. In both the 499 and 502
branches, mark the active span failed and attach the proxy error as an error
attribute before responding.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/invocation-plane-services/vanity-gateway/gateway/vanity_director.go`:
- Around line 83-106: Update writeProxyError and its ServeExec call site to
thread target.FunctionID and target.FunctionVersionID into the disconnect path.
Include all available request context fields—Request ID, Function ID, Cluster
ID, and Org/NCA ID—in the client-disconnect warning. In both the 499 and 502
branches, mark the active span failed and attach the proxy error as an error
attribute before responding.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8cd868a1-fa6c-43aa-85f8-4dec2c837cb0

📥 Commits

Reviewing files that changed from the base of the PR and between 6a8ed21 and da503e7.

📒 Files selected for processing (4)
  • src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs
  • src/invocation-plane-services/http-invocation/crates/server/src/routes/post_pexec.rs
  • src/invocation-plane-services/vanity-gateway/gateway/vanity_director.go
  • src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go

// Pre-init the 499 series so it reports 0 before the first disconnect.
counter!(
FUNCTION_INVOCATION_ERROR.name,
"http_status_code" => "499",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should make 499 a env var and use it spread around

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, declared the var as a constant not a env var

assert_eq!(value, DebugValue::Counter(1));
}

/// A server-side early exit (status was returned) must NOT be counted as a 499.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally should reference 499 as client early disconnect. 499 is not a true standard error code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need changed to the vanity gateway. It should be recording the 499 regardless. Did you test e2e to see if that was the case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested - the gateway change is needed. Added an integration test running the real otelhttp middleware over ServeExec: a canceled inbound context records status_code=499 a genuine upstream error records 502. otelhttp records whatever status the error handler writes without the change it writes 502 for disconnects too. Not cross-service e2e, but it hits the exact metric-emitting path.

…layer

Add integration tests that drive a request through the real otelhttp server
middleware wrapping ServeExec and read back http.server.request.duration:
a canceled inbound context records status_code=499, a genuine upstream
transport error records 502. This is the concrete evidence that the gateway
change is what makes disconnects countable as 499 (otelhttp records whatever
status the proxy error handler writes).

Also centralize the "499" literal into metrics::CLIENT_EARLY_DISCONNECT_STATUS
and use "client early disconnect" wording in logs, comments, and tests per
review feedback.

Relates to #524

Signed-off-by: shobham <shobham@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs (1)

210-218: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add regression coverage for the pre-initialized 499 series.

The existing test covers status 504, not the zero-valued app.invocation.error{http_status_code="499",function_id=""} series before the first disconnect. Add this test or explain the omission in the Pull Request description.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs`
around lines 210 - 218, Add regression coverage near the existing metrics test
for the pre-initialized CLIENT_EARLY_DISCONNECT_STATUS series: verify
app.invocation.error with http_status_code "499" and an empty function_id is
present with value 0 before any disconnect occurs. Keep the existing 504
coverage unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go`:
- Around line 582-610: Update gatewayMetricHasStatusCode to skip histogram data
points whose point.Count is zero before checking the http.response.status_code
attribute, so it only reports metrics containing a recorded observation.

---

Outside diff comments:
In
`@src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs`:
- Around line 210-218: Add regression coverage near the existing metrics test
for the pre-initialized CLIENT_EARLY_DISCONNECT_STATUS series: verify
app.invocation.error with http_status_code "499" and an empty function_id is
present with value 0 before any disconnect occurs. Keep the existing 504
coverage unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ca628f87-2158-4d30-ada0-74801b72c61f

📥 Commits

Reviewing files that changed from the base of the PR and between da503e7 and 597cca0.

📒 Files selected for processing (3)
  • src/invocation-plane-services/http-invocation/crates/server/src/metrics/mod.rs
  • src/invocation-plane-services/http-invocation/crates/server/src/routes/post_pexec.rs
  • src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/invocation-plane-services/http-invocation/crates/server/src/routes/post_pexec.rs

Comment on lines +582 to +610
func collectGatewayMetrics(t *testing.T, reader sdkmetric.Reader) []metricdata.Metrics {
t.Helper()
var rm metricdata.ResourceMetrics
require.NoError(t, reader.Collect(context.Background(), &rm))
var out []metricdata.Metrics
for _, sm := range rm.ScopeMetrics {
out = append(out, sm.Metrics...)
}
return out
}

func gatewayMetricHasStatusCode(metrics []metricdata.Metrics, code int) bool {
for _, metric := range metrics {
if metric.Name != "http.server.request.duration" {
continue
}
histogram, ok := metric.Data.(metricdata.Histogram[float64])
if !ok {
continue
}
for _, point := range histogram.DataPoints {
if value, ok := point.Attributes.Value("http.response.status_code"); ok &&
value == attribute.Int64Value(int64(code)) {
return true
}
}
}
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '540,630p' src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go
printf '\n--- metric helper usages ---\n'
rg -n -C 3 'gatewayMetricHasStatusCode|collectGatewayMetrics|http\.server\.request\.duration' src/invocation-plane-services/vanity-gateway/gateway

Repository: NVIDIA/nvcf

Length of output: 7611


🏁 Script executed:

printf '%s\n' '--- OpenTelemetry versions ---'
rg -n -C 2 'opentelemetry|otelhttp' go.mod '**/go.mod' 2>/dev/null || true
printf '%s\n' '--- local metricdata definitions ---'
rg -n -C 4 'type Histogram|type HistogramDataPoint|Count[[:space:]]+uint64' . --glob '*.go' --glob '!vendor/**' | head -200
printf '%s\n' '--- module cache candidates ---'
find "${GOMODCACHE:-/go/pkg/mod}" -path '*opentelemetry*metricdata*data.go' -o -path '*opentelemetry*metricdata*' 2>/dev/null | head -40

Repository: NVIDIA/nvcf

Length of output: 22721


🏁 Script executed:

git ls-files | rg '(^|/)go\.mod$|vendor/.*/opentelemetry|vanity_director_test\.go$'
printf '%s\n' '--- relevant module files ---'
for f in $(git ls-files | rg '(^|/)go\.mod$'); do
  if rg -q 'opentelemetry|otelhttp' "$f"; then
    printf '\n%s\n' "$f"
    rg -n -C 2 'opentelemetry|otelhttp' "$f"
  fi
done

Repository: NVIDIA/nvcf

Length of output: 35571


🌐 Web query:

OpenTelemetry Go v1.43.0 metricdata Histogram DataPoint Count zero-count data points SDK ManualReader

💡 Result:

In OpenTelemetry Go v1.43.0, the metricdata.HistogramDataPoint structure contains a Count field (a uint64) that represents the total number of updates recorded for that histogram [1][2]. For exponential histograms specifically, there is also a ZeroCount field. This field tracks the number of values whose absolute value falls within the histogram's "zero region," defined by the ZeroThreshold [1][2]. This is not a "zero-count" in the sense of zero updates, but rather a dedicated bucket for values too small to be represented by the exponential formula or values rounded to zero [1][2]. Regarding your query about ManualReader and histogram behavior: 1. Data Collection: ManualReader uses the Collect method to trigger the SDK to produce and gather metric data into metricdata.ResourceMetrics [3]. It does not inherently alter the internal logic of how HistogramDataPoint counts are calculated; it simply facilitates the export of the current state of those aggregations [3]. 2. Potential for Stale Data: There have been identified issues in the SDK regarding the reuse of HistogramDataPoint entries [4]. Specifically, if a HistogramDataPoint is reused across collection cycles, fields such as Sum, Min, Max, or Count may retain stale values if they are not explicitly cleared or if specific aggregation options (like NoMinMax=true) are changed between collections [4]. While not limited to ManualReader, this behavior affects any reader that collects from an aggregation where internal state is recycled [4]. 3. Recent SDK Updates: It is worth noting that v1.43.0 included significant updates to how exponential histograms handle their internal state, including switching to atomic operations for sum, min, max, and count to ensure concurrency safety [5]. Additionally, a race condition affecting LastValue aggregations—where a zero value could be incorrectly observed—was resolved in this release [6][5]. If you are seeing unexpected count values, ensure that your aggregation configuration is consistent and consider that stale data might persist if the SDK is reusing underlying aggregation objects across collection cycles [4].

Citations:


🏁 Script executed:

set -eu
base='https://raw.githubusercontent.com/open-telemetry/opentelemetry-go/v1.43.0'
for path in \
  sdk/metric/metricdata/data.go \
  sdk/metric/aggregation.go \
  sdk/metric/aggregation_histogram.go \
  sdk/metric/manual_reader.go
do
  printf '\n--- %s ---\n' "$path"
  curl -fsSL "$base/$path" | rg -n -C 5 'type Histogram|Count|DataPoints|metricdata\.Histogram|Export'
done

Repository: NVIDIA/nvcf

Length of output: 6018


🏁 Script executed:

set -eu
curl -fsSL 'https://api.github.com/repos/open-telemetry/opentelemetry-go/git/trees/v1.43.0?recursive=1' |
  jq -r '.tree[].path' |
  rg '^sdk/metric/.*(histogram|aggregation|manual_reader).*\.go$'

Repository: NVIDIA/nvcf

Length of output: 198


🌐 Web query:

site:github.com/open-telemetry/opentelemetry-go/blob/v1.43.0/sdk/metric "HistogramDataPoint" "Count" "DataPoints"

💡 Result:

In OpenTelemetry Go v1.43.0:

  • Histogram.DataPoints is typed as []HistogramDataPoint[N].
  • HistogramDataPoint.Count is a uint64 representing the number of updates used to calculate the histogram.
  • The relevant definition is in sdk/metric/metricdata/data.go, lines 971–1019. (github.com)
type Histogram[N int64 | float64] struct {
    DataPoints []HistogramDataPoint[N]
}

type HistogramDataPoint[N int64 | float64] struct {
    Count        uint64
    Bounds       []float64
    BucketCounts []uint64
    Sum          N
}

Citations:


Require a non-zero histogram count.

Skip points with point.Count == 0 before matching http.response.status_code. This ensures the helper identifies a recorded observation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/invocation-plane-services/vanity-gateway/gateway/vanity_director_test.go`
around lines 582 - 610, Update gatewayMetricHasStatusCode to skip histogram data
points whose point.Count is zero before checking the http.response.status_code
attribute, so it only reports metrics containing a recorded observation.

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.

feat(http-invocation): classify client disconnects as HTTP 499

2 participants