Skip to content

feat: add duration and traceId to degraded events#8455

Merged
mcmire merged 29 commits intomainfrom
feat/degraded-event-duration-traceid
May 5, 2026
Merged

feat: add duration and traceId to degraded events#8455
mcmire merged 29 commits intomainfrom
feat/degraded-event-duration-traceid

Conversation

@cryptodev-2s
Copy link
Copy Markdown
Contributor

@cryptodev-2s cryptodev-2s commented Apr 14, 2026

Explanation

RPC endpoint degraded events (NetworkController:rpcEndpointDegraded and NetworkController:rpcEndpointChainDegraded) now include two new optional properties in their payloads:

  • duration (number | undefined): The policy execution time in milliseconds when the request succeeded but was slow (i.e., exceeded the degradedThreshold). This is undefined when the degraded event was caused by retries being exhausted.

  • traceId (string | undefined): The value of the x-trace-id response header from the last request attempt. This enables correlating degraded events with backend traces for debugging RPC health issues. It is undefined when no response was received or the header was not present.

How it works

The duration value originates from Cockatiel's retryPolicy.onSuccess callback in createServicePolicy. Previously, it was only used for the threshold comparison — now it is also emitted as part of the degraded event data.

The traceId is captured in RpcService from response.headers.get('x-trace-id') in the same finally block that tracks rpcMethodName, ensuring it reflects the last completed request attempt (handling concurrent request race conditions correctly).

Both values are threaded through the event chain: createServicePolicyRpcServiceRpcServiceChaincreateNetworkClient → messenger events.

Breaking change

The RpcServiceRequestable type's onDegraded listener signature now includes duration?: number and traceId?: string in its data parameter. Implementors of this interface will need to accept the new fields in their onDegraded callback signature.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
This is a breaking, cross-package event/type change that affects all onDegraded/messenger subscribers and could cause downstream TypeScript or runtime assumptions to fail if payload handling isn’t updated. Logic changes are small but touch retry/degraded signaling and request metadata capture.

Overview
Degraded-event payloads now include more diagnostics. createServicePolicy’s onDegraded event no longer emits void for slow successes; it emits { duration: number }, and tests were updated accordingly.

Network degraded messenger events are extended. NetworkController:rpcEndpointDegraded and NetworkController:rpcEndpointChainDegraded payloads add optional duration (slow success) and traceId (last response X-Trace-Id header), with plumbing added from RpcService through RpcServiceChain/createNetworkClient and expanded test coverage (including avoiding stale traceId when a retry throws before a response).

Reviewed by Cursor Bugbot for commit 9867d45. Bugbot is set up for automated code reviews on this repo. Configure here.

@cryptodev-2s cryptodev-2s force-pushed the feat/degraded-event-duration-traceid branch from e3eb1a1 to c4cf4d5 Compare April 14, 2026 19:03
@cryptodev-2s
Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.0.0-preview-c4cf4d5
@metamask-previews/accounts-controller@37.2.0-preview-c4cf4d5
@metamask-previews/address-book-controller@7.1.1-preview-c4cf4d5
@metamask-previews/ai-controllers@0.6.3-preview-c4cf4d5
@metamask-previews/analytics-controller@1.0.1-preview-c4cf4d5
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-c4cf4d5
@metamask-previews/announcement-controller@8.1.0-preview-c4cf4d5
@metamask-previews/app-metadata-controller@2.0.1-preview-c4cf4d5
@metamask-previews/approval-controller@9.0.1-preview-c4cf4d5
@metamask-previews/assets-controller@5.0.0-preview-c4cf4d5
@metamask-previews/assets-controllers@103.1.1-preview-c4cf4d5
@metamask-previews/base-controller@9.1.0-preview-c4cf4d5
@metamask-previews/base-data-service@0.1.1-preview-c4cf4d5
@metamask-previews/bridge-controller@70.0.1-preview-c4cf4d5
@metamask-previews/bridge-status-controller@70.0.5-preview-c4cf4d5
@metamask-previews/build-utils@3.0.4-preview-c4cf4d5
@metamask-previews/chain-agnostic-permission@1.5.0-preview-c4cf4d5
@metamask-previews/claims-controller@0.5.0-preview-c4cf4d5
@metamask-previews/client-controller@1.0.1-preview-c4cf4d5
@metamask-previews/compliance-controller@2.0.0-preview-c4cf4d5
@metamask-previews/composable-controller@12.0.1-preview-c4cf4d5
@metamask-previews/config-registry-controller@0.2.0-preview-c4cf4d5
@metamask-previews/connectivity-controller@0.2.0-preview-c4cf4d5
@metamask-previews/controller-utils@11.20.0-preview-c4cf4d5
@metamask-previews/core-backend@6.2.1-preview-c4cf4d5
@metamask-previews/delegation-controller@3.0.0-preview-c4cf4d5
@metamask-previews/earn-controller@12.0.0-preview-c4cf4d5
@metamask-previews/eip-5792-middleware@3.0.3-preview-c4cf4d5
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-c4cf4d5
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-c4cf4d5
@metamask-previews/ens-controller@19.1.1-preview-c4cf4d5
@metamask-previews/eth-block-tracker@15.0.1-preview-c4cf4d5
@metamask-previews/eth-json-rpc-middleware@23.1.1-preview-c4cf4d5
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-c4cf4d5
@metamask-previews/foundryup@1.0.1-preview-c4cf4d5
@metamask-previews/gas-fee-controller@26.1.1-preview-c4cf4d5
@metamask-previews/gator-permissions-controller@3.0.1-preview-c4cf4d5
@metamask-previews/geolocation-controller@0.1.2-preview-c4cf4d5
@metamask-previews/json-rpc-engine@10.2.4-preview-c4cf4d5
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-c4cf4d5
@metamask-previews/keyring-controller@25.2.0-preview-c4cf4d5
@metamask-previews/logging-controller@8.0.1-preview-c4cf4d5
@metamask-previews/message-manager@14.1.1-preview-c4cf4d5
@metamask-previews/messenger@1.1.1-preview-c4cf4d5
@metamask-previews/messenger-cli@0.1.0-preview-c4cf4d5
@metamask-previews/money-account-controller@0.1.0-preview-c4cf4d5
@metamask-previews/multichain-account-service@8.0.1-preview-c4cf4d5
@metamask-previews/multichain-api-middleware@2.0.0-preview-c4cf4d5
@metamask-previews/multichain-network-controller@3.0.6-preview-c4cf4d5
@metamask-previews/multichain-transactions-controller@7.0.4-preview-c4cf4d5
@metamask-previews/name-controller@9.1.1-preview-c4cf4d5
@metamask-previews/network-controller@30.0.1-preview-c4cf4d5
@metamask-previews/network-enablement-controller@5.0.2-preview-c4cf4d5
@metamask-previews/notification-services-controller@23.1.0-preview-c4cf4d5
@metamask-previews/permission-controller@12.3.0-preview-c4cf4d5
@metamask-previews/permission-log-controller@5.1.0-preview-c4cf4d5
@metamask-previews/perps-controller@3.0.0-preview-c4cf4d5
@metamask-previews/phishing-controller@17.1.1-preview-c4cf4d5
@metamask-previews/polling-controller@16.0.4-preview-c4cf4d5
@metamask-previews/preferences-controller@23.1.0-preview-c4cf4d5
@metamask-previews/profile-metrics-controller@3.1.3-preview-c4cf4d5
@metamask-previews/profile-sync-controller@28.0.2-preview-c4cf4d5
@metamask-previews/ramps-controller@13.1.0-preview-c4cf4d5
@metamask-previews/rate-limit-controller@7.0.1-preview-c4cf4d5
@metamask-previews/react-data-query@0.2.0-preview-c4cf4d5
@metamask-previews/remote-feature-flag-controller@4.2.0-preview-c4cf4d5
@metamask-previews/sample-controllers@4.0.4-preview-c4cf4d5
@metamask-previews/seedless-onboarding-controller@9.1.0-preview-c4cf4d5
@metamask-previews/selected-network-controller@26.1.0-preview-c4cf4d5
@metamask-previews/shield-controller@5.1.1-preview-c4cf4d5
@metamask-previews/signature-controller@39.1.2-preview-c4cf4d5
@metamask-previews/social-controllers@0.1.0-preview-c4cf4d5
@metamask-previews/storage-service@1.0.1-preview-c4cf4d5
@metamask-previews/subscription-controller@6.1.2-preview-c4cf4d5
@metamask-previews/transaction-controller@64.2.0-preview-c4cf4d5
@metamask-previews/transaction-pay-controller@19.1.1-preview-c4cf4d5
@metamask-previews/user-operation-controller@41.2.0-preview-c4cf4d5

@cryptodev-2s cryptodev-2s force-pushed the feat/degraded-event-duration-traceid branch from b9ab587 to e8262db Compare April 14, 2026 20:14
@cryptodev-2s cryptodev-2s marked this pull request as ready for review April 14, 2026 20:50
@cryptodev-2s cryptodev-2s requested review from a team as code owners April 14, 2026 20:50
@cryptodev-2s cryptodev-2s self-assigned this Apr 14, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4fd9aedc6833f2458d4ee8749632ebaa137599a8. Configure here.

Comment thread packages/network-controller/src/rpc-service/rpc-service.ts Outdated
@cryptodev-2s
Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

1 similar comment
@cryptodev-2s
Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions
Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.0.0-preview-e61cfa5
@metamask-previews/accounts-controller@37.2.0-preview-e61cfa5
@metamask-previews/address-book-controller@7.1.1-preview-e61cfa5
@metamask-previews/ai-controllers@0.6.3-preview-e61cfa5
@metamask-previews/analytics-controller@1.0.1-preview-e61cfa5
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-e61cfa5
@metamask-previews/announcement-controller@8.1.0-preview-e61cfa5
@metamask-previews/app-metadata-controller@2.0.1-preview-e61cfa5
@metamask-previews/approval-controller@9.0.1-preview-e61cfa5
@metamask-previews/assets-controller@5.0.0-preview-e61cfa5
@metamask-previews/assets-controllers@103.1.1-preview-e61cfa5
@metamask-previews/base-controller@9.0.1-preview-e61cfa5
@metamask-previews/base-data-service@0.1.1-preview-e61cfa5
@metamask-previews/bridge-controller@70.0.1-preview-e61cfa5
@metamask-previews/bridge-status-controller@70.0.5-preview-e61cfa5
@metamask-previews/build-utils@3.0.4-preview-e61cfa5
@metamask-previews/chain-agnostic-permission@1.5.0-preview-e61cfa5
@metamask-previews/claims-controller@0.5.0-preview-e61cfa5
@metamask-previews/client-controller@1.0.1-preview-e61cfa5
@metamask-previews/compliance-controller@2.0.0-preview-e61cfa5
@metamask-previews/composable-controller@12.0.1-preview-e61cfa5
@metamask-previews/config-registry-controller@0.2.0-preview-e61cfa5
@metamask-previews/connectivity-controller@0.2.0-preview-e61cfa5
@metamask-previews/controller-utils@11.20.0-preview-e61cfa5
@metamask-previews/core-backend@6.2.1-preview-e61cfa5
@metamask-previews/delegation-controller@3.0.0-preview-e61cfa5
@metamask-previews/earn-controller@12.0.0-preview-e61cfa5
@metamask-previews/eip-5792-middleware@3.0.3-preview-e61cfa5
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-e61cfa5
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-e61cfa5
@metamask-previews/ens-controller@19.1.1-preview-e61cfa5
@metamask-previews/eth-block-tracker@15.0.1-preview-e61cfa5
@metamask-previews/eth-json-rpc-middleware@23.1.1-preview-e61cfa5
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-e61cfa5
@metamask-previews/foundryup@1.0.1-preview-e61cfa5
@metamask-previews/gas-fee-controller@26.1.1-preview-e61cfa5
@metamask-previews/gator-permissions-controller@3.0.1-preview-e61cfa5
@metamask-previews/geolocation-controller@0.1.2-preview-e61cfa5
@metamask-previews/json-rpc-engine@10.2.4-preview-e61cfa5
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-e61cfa5
@metamask-previews/keyring-controller@25.2.0-preview-e61cfa5
@metamask-previews/logging-controller@8.0.1-preview-e61cfa5
@metamask-previews/message-manager@14.1.1-preview-e61cfa5
@metamask-previews/messenger@1.1.1-preview-e61cfa5
@metamask-previews/messenger-cli@0.1.0-preview-e61cfa5
@metamask-previews/money-account-controller@0.1.0-preview-e61cfa5
@metamask-previews/multichain-account-service@8.0.1-preview-e61cfa5
@metamask-previews/multichain-api-middleware@2.0.0-preview-e61cfa5
@metamask-previews/multichain-network-controller@3.0.6-preview-e61cfa5
@metamask-previews/multichain-transactions-controller@7.0.4-preview-e61cfa5
@metamask-previews/name-controller@9.1.1-preview-e61cfa5
@metamask-previews/network-controller@30.0.1-preview-e61cfa5
@metamask-previews/network-enablement-controller@5.0.2-preview-e61cfa5
@metamask-previews/notification-services-controller@23.1.0-preview-e61cfa5
@metamask-previews/permission-controller@12.3.0-preview-e61cfa5
@metamask-previews/permission-log-controller@5.1.0-preview-e61cfa5
@metamask-previews/perps-controller@3.0.0-preview-e61cfa5
@metamask-previews/phishing-controller@17.1.1-preview-e61cfa5
@metamask-previews/polling-controller@16.0.4-preview-e61cfa5
@metamask-previews/preferences-controller@23.1.0-preview-e61cfa5
@metamask-previews/profile-metrics-controller@3.1.3-preview-e61cfa5
@metamask-previews/profile-sync-controller@28.0.2-preview-e61cfa5
@metamask-previews/ramps-controller@13.1.0-preview-e61cfa5
@metamask-previews/rate-limit-controller@7.0.1-preview-e61cfa5
@metamask-previews/react-data-query@0.2.0-preview-e61cfa5
@metamask-previews/remote-feature-flag-controller@4.2.0-preview-e61cfa5
@metamask-previews/sample-controllers@4.0.4-preview-e61cfa5
@metamask-previews/seedless-onboarding-controller@9.1.0-preview-e61cfa5
@metamask-previews/selected-network-controller@26.1.0-preview-e61cfa5
@metamask-previews/shield-controller@5.1.1-preview-e61cfa5
@metamask-previews/signature-controller@39.1.2-preview-e61cfa5
@metamask-previews/social-controllers@0.1.0-preview-e61cfa5
@metamask-previews/storage-service@1.0.1-preview-e61cfa5
@metamask-previews/subscription-controller@6.1.2-preview-e61cfa5
@metamask-previews/transaction-controller@64.2.0-preview-e61cfa5
@metamask-previews/transaction-pay-controller@19.1.1-preview-e61cfa5
@metamask-previews/user-operation-controller@41.2.0-preview-e61cfa5

@cryptodev-2s cryptodev-2s force-pushed the feat/degraded-event-duration-traceid branch from e61cfa5 to 10f285d Compare April 15, 2026 08:51
@cryptodev-2s cryptodev-2s requested a review from mcmire April 15, 2026 14:09
When a request succeeds but takes longer than degradedThreshold,
the onDegraded event now emits { duration } instead of void, so
higher layers can include the actual request duration in their
event payloads.
@cryptodev-2s
Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

Comment on lines 455 to 471
const commonFields = {
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
traceId: this.#currentTraceId,
};
if (hasProperty(data, 'duration') && typeof data.duration === 'number') {
listener({
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
...commonFields,
duration: data.duration,
});
} else {
listener({
...data,
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
...commonFields,
duration: undefined,
});
}
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.

There still seem to be some type errors here. I think this can just be:

Suggested change
const commonFields = {
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
traceId: this.#currentTraceId,
};
if (hasProperty(data, 'duration') && typeof data.duration === 'number') {
listener({
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
...commonFields,
duration: data.duration,
});
} else {
listener({
...data,
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
...commonFields,
duration: undefined,
});
}
listener({
...data,
endpointUrl: this.endpointUrl.toString(),
rpcMethodName: this.#currentRpcMethodName,
traceId: this.#currentTraceId,
});

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.

Fixed here: 0e695d0


### Changed

- **BREAKING:** The `RpcServiceRequestable` type's `onDegraded` listener now receives `duration?: number` and `traceId?: string` in its data parameter ([#8455](https://github.com/MetaMask/core/pull/8455))
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've been meaning to get rid of this type as we don't really need it anymore. If we change RpcService not to implement this interface anymore then we don't need to change this type at all, and we can avoid the breaking change here. May be worth doing that before merging this.

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've made the change I mentioned here: #8475

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've removed the changes from RpcServiceRequestable as well as the changelog here: 0e695d0

payload: [
{
chainId: Hex;
duration?: number;
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 have to check to make sure that this also isn't a breaking change. I thought at first it wasn't, but then given that event payloads show up as arguments to callbacks, I am having second doubts.

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.

Traditionally we have not treated additional payload properties as breaking, but I think we should, so that's what I've done here.

mcmire
mcmire previously approved these changes Apr 22, 2026
Copy link
Copy Markdown
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

LGTM.

@mcmire mcmire enabled auto-merge April 22, 2026 18:28
mcmire
mcmire previously approved these changes Apr 22, 2026
@mcmire mcmire disabled auto-merge April 22, 2026 19:10
@mcmire mcmire enabled auto-merge April 22, 2026 19:10
mcmire
mcmire previously approved these changes Apr 22, 2026
@cryptodev-2s cryptodev-2s requested a review from mcmire May 5, 2026 14:28
Copy link
Copy Markdown
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

LGTM!

@mcmire mcmire added this pull request to the merge queue May 5, 2026
Merged via the queue into main with commit b6146e5 May 5, 2026
366 checks passed
@mcmire mcmire deleted the feat/degraded-event-duration-traceid branch May 5, 2026 14:36
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.

2 participants