Skip to content

Commit 2c7678c

Browse files
committed
Revamp NetworkController RPC endpoint events
In a future commit we will introduce changes to `network-controller` so that it will keep track of the status of each network as requests are made. This commit paves the way for this to happen by redefining the existing RPC endpoint-related events that NetworkController produces. Currently, when requests are made through the network clients that NetworkController exposes, three events are published: - `NetworkController:rpcEndpointDegraded` - Published when enough successive retriable errors are encountered while making a request to an RPC endpoint that the maximum number of retries is reached. - `NetworkController:rpcEndpointUnavailable` - Published when enough successive errors are encountered while making a request to an RPC endpoint that the underlying circuit breaks. - `NetworkController:rpcEndpointRequestRetried` - Published when a request is retried (mainly used for testing). It's important to note that in the context of the RPC failover feature, an "RPC endpoint" can actually encompass multiple URLs, so the above events actually fire for any URL. While these events are useful for reporting metrics on RPC endpoints, in order to effectively be able to update the status of a network, we need events that are less granular and are guaranteed not to fire multiple times in a row. We also need a new event. Now the list of events looks like this: - `NetworkController:rpcEndpointInstanceDegraded` - The same as `NetworkController:rpcEndpointDegraded` before. - `NetworkController:rpcEndpointInstanceUnavailable` - The same as `NetworkController:rpcEndpointInstanceDegraded` before. - `NetworkController:rpcEndpointInstanceRetried` - Renamed from `NetworkController:rpcEndpointRequestRetried`. - `NetworkController:rpcEndpointDegraded` - Similar to `NetworkController:rpcEndpointInstanceDegraded`, but won't be published again if the RPC endpoint is already in a degraded state. - `NetworkController:rpcEndpointUnavailable` - Published when all of the circuits underlying all of the URLs for an RPC endpoint have broken (none of the URLs are available). Won't be published again if the RPC endpoint is already in an unavailable state. - `NetworkController:rpcEndpointAvailable` - A new event. Published the first time a successful request is made to one of the URLs for an RPC endpoint, or following a degraded or unavailable status.
1 parent 246b2b5 commit 2c7678c

18 files changed

+4858
-1980
lines changed

packages/network-controller/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `NetworkController:rpcEndpointAvailable` messenger event ([#7166](https://github.com/MetaMask/core/pull/7166))
13+
- These are counterparts to the (new) `NetworkController:rpcEndpointUnavailable` and `NetworkController:rpcEndpointDegraded` events, but are published when a request to an RPC endpoint URL is made either initially or following a previously established degraded or unavailable status.
14+
1015
### Changed
1116

1217
- **BREAKING:** Use `InternalProvider` instead of `SafeEventEmitterProvider` ([#6796](https://github.com/MetaMask/core/pull/6796))
@@ -19,6 +24,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1924
- In practice, this should happen rarely if ever.
2025
- **BREAKING:** Migrate `NetworkClient` to `JsonRpcEngineV2` ([#7065](https://github.com/MetaMask/core/pull/7065))
2126
- This ought to be unobservable, but we mark it as breaking out of an abundance of caution.
27+
- **BREAKING:** Split up and update payload data for `NetworkController:rpcEndpoint{Degraded,Unavailable}` ([#7166](https://github.com/MetaMask/core/pull/7166))
28+
- The existing events are now called `NetworkController:rpcEndpointInstance{Degraded,Unavailable}` and retain their present behavior.
29+
- `NetworkController:rpcEndpointInstance{Degraded,Unavailable}` do still exist, but they are now designed to represent the entire RPC endpoint and are guaranteed to not be published multiple times in a row. In particular, `NetworkController:rpcEndpointUnavailable` is published only after trying all of the designated URLs for a particular RPC endpoint and the underlying circuit for the last URL breaks, not as each primary's or failover's circuit breaks.
30+
- The event payloads have been changed as well: `failoverEndpointUrl` has been renamed to `endpointUrl`, and `endpointUrl` has been renamed to `primaryEndpointUrl`. In addition, `networkClientId` has been added.
31+
- **BREAKING:** Rename and update payload data for `NetworkController:rpcEndpointRequestRetried` ([#7166](https://github.com/MetaMask/core/pull/7166))
32+
- This event is now called `NetworkController:rpcEndpointInstanceRequestRetried`
33+
- The event payload has been changed as well: `failoverEndpointUrl` has been renamed to `endpointUrl`, and `endpointUrl` has been renamed to `primaryEndpointUrl`. In addition, `networkClientId` and `attempt` have been added.
34+
- **BREAKING:** Update `AbstractRpcService`/`RpcServiceRequestable` to remove `{ isolated: true }` from the `onBreak` event data type ([#7166](https://github.com/MetaMask/core/pull/7166))
35+
- This represented the error produced when `.isolate` is called on a Cockatiel circuit breaker policy, which we never do.
2236
- Bump `@metamask/controller-utils` from `^11.14.1` to `^11.15.0` ([#7003](https://github.com/MetaMask/core/pull/7003))
2337

2438
### Fixed

packages/network-controller/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"@types/jest-when": "^2.7.3",
7979
"@types/lodash": "^4.14.191",
8080
"@types/node-fetch": "^2.6.12",
81+
"cockatiel": "^3.1.2",
8182
"deep-freeze-strict": "^1.1.1",
8283
"deepmerge": "^4.2.2",
8384
"jest": "^27.5.1",

packages/network-controller/src/NetworkController.ts

Lines changed: 195 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -443,25 +443,109 @@ export type NetworkControllerNetworkRemovedEvent = {
443443
};
444444

445445
/**
446-
* `rpcEndpointUnavailable` is published after an attempt to make a request to
447-
* an RPC endpoint fails too many times in a row (because of a connection error
448-
* or an unusable response).
446+
* `NetworkController:rpcEndpointUnavailable` is published when the number of
447+
* failed consecutive attempts to receive a 2xx response from the primary URL of
448+
* an RPC endpoint reaches a maximum, causing further requests to be temporarily
449+
* paused, and when subsequent traffic to a failover URL similarly fails.
450+
*
451+
* In other words, this event will not published if a primary is deemed to be
452+
* unavailable but its failover is not.
453+
*
454+
* Additionally, if this was the last `NetworkController:rpcEndpoint*` event to
455+
* be published, the event will not be re-published (for instance, if both a
456+
* primary and failover are deemed to be unavailable, or if more than one
457+
* failover is deemed to be unavailable).
458+
*
459+
* @param payload - The event payload.
460+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
461+
* lives.
462+
* @param payload.networkClientId - The ID of the network client representing
463+
* the RPC endpoint.
464+
* @param payload.primaryEndpointUrl - The primary URL of the endpoint.
465+
* @param payload.endpointUrl - One of the URLs defined for the endpoint which
466+
* has been deemed to be unavailable.
467+
* @param payload.error - The error from the last request to one of the URLs
468+
* defined for the endpoint which determined the unavailability status.
449469
*/
450470
export type NetworkControllerRpcEndpointUnavailableEvent = {
451471
type: 'NetworkController:rpcEndpointUnavailable';
452472
payload: [
453473
{
454474
chainId: Hex;
455475
endpointUrl: string;
456-
failoverEndpointUrl?: string;
457476
error: unknown;
477+
networkClientId: NetworkClientId;
478+
primaryEndpointUrl: string;
458479
},
459480
];
460481
};
461482

462483
/**
463-
* `rpcEndpointDegraded` is published after a request to an RPC endpoint
464-
* responds successfully but takes too long.
484+
* `NetworkController:rpcEndpointInstanceUnavailable` is published when the
485+
* number of failed consecutive attempts to receive a 2xx response from *any* of
486+
* the designated URLs of an RPC endpoint reaches a maximum.
487+
*
488+
* This event will still be published if a primary is deemed to be unavailable,
489+
* even its failover is available.
490+
*
491+
* Additionally, even if this was the last `NetworkController:rpcEndpoint*` event
492+
* to be published, the event may be re-published (for instance, if both a
493+
* primary and failover are deemed to be unavailable, or if more than one
494+
* failover is deemed to be unavailable).
495+
*
496+
* @param payload - The event payload.
497+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
498+
* lives.
499+
* @param payload.networkClientId - The ID of the network client representing
500+
* the RPC endpoint.
501+
* @param payload.primaryEndpointUrl - The primary URL of the endpoint.
502+
* @param payload.endpointUrl - One of the URLs defined for the endpoint which
503+
* has been deemed to be unavailable.
504+
* @param payload.error - The error from the last request to the `endpointUrl`
505+
* which determined the unavailability status.
506+
*/
507+
export type NetworkControllerRpcEndpointInstanceUnavailableEvent = {
508+
type: 'NetworkController:rpcEndpointInstanceUnavailable';
509+
payload: [
510+
{
511+
chainId: Hex;
512+
endpointUrl: string;
513+
error: unknown;
514+
networkClientId: NetworkClientId;
515+
primaryEndpointUrl: string;
516+
},
517+
];
518+
};
519+
520+
/**
521+
* `NetworkController:rpcEndpointDegraded` is published in the following two
522+
* cases:
523+
*
524+
* 1. When an attempt to receive a 2xx response from any of the designated URLs
525+
* for an RPC endpoint is unsuccessful, and all subsequent automatic retries
526+
* lead to the same result.
527+
* 2. When a 2xx response is received from any of the endpoint URLs, but the
528+
* request takes longer than a set number of seconds to complete.
529+
*
530+
* Note that this event will be published even if there are local connectivity
531+
* issues which prevent requests from being initiated. This is intentional.
532+
*
533+
* Additionally, if this was the last `NetworkController:rpcEndpoint*` event to
534+
* be published, the event will not be re-published (for instance: a failover is
535+
* activated and successive attempts to the failover fail, then the primary
536+
* comes back online, but it is slow).
537+
*
538+
* @param payload - The event payload.
539+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
540+
* lives.
541+
* @param payload.networkClientId - The ID of the network client representing
542+
* the RPC endpoint.
543+
* @param payload.primaryEndpointUrl - The primary URL of the endpoint.
544+
* @param payload.endpointUrl - One of the URLs defined for the endpoint which
545+
* has been deemed to be degraded.
546+
* @param payload.error - The error from the last request to the `endpointUrl`
547+
* which determined the degraded status (or `undefined` if the request was
548+
* merely slow).
465549
*/
466550
export type NetworkControllerRpcEndpointDegradedEvent = {
467551
type: 'NetworkController:rpcEndpointDegraded';
@@ -470,20 +554,113 @@ export type NetworkControllerRpcEndpointDegradedEvent = {
470554
chainId: Hex;
471555
endpointUrl: string;
472556
error: unknown;
557+
networkClientId: NetworkClientId;
558+
primaryEndpointUrl: string;
473559
},
474560
];
475561
};
476562

477563
/**
478-
* `rpcEndpointRequestRetried` is published after a request to an RPC endpoint
479-
* is retried following a connection error or an unusable response.
564+
*
565+
* `NetworkController:rpcEndpointInstanceDegraded` is published in the following
566+
* two cases:
567+
*
568+
* 1. When an attempt to receive a 2xx response from *any* of the designated
569+
* URLs for an RPC endpoint is unsuccessful, and all subsequent automatic
570+
* retries lead to the same result.
571+
* 2. When a 2xx response is received from any of the endpoint URLs, but the
572+
* request takes longer than a set number of seconds to complete.
573+
*
574+
* Note that this event will be published even if there are local connectivity
575+
* issues which prevent requests from being initiated. This is intentional.
576+
*
577+
* Additionally, if this was the last `NetworkController:rpcEndpoint*` event to
578+
* be published, the event may be re-published (for instance: a failover is
579+
* activated and successive attempts to the failover fail, then the primary
580+
* comes back online, but it is slow).
581+
*
582+
* @param payload - The event payload.
583+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
584+
* lives.
585+
* @param payload.networkClientId - The ID of the network client representing
586+
* the RPC endpoint.
587+
* @param payload.primaryEndpointUrl - The primary URL of the endpoint.
588+
* @param payload.endpointUrl - One of the URLs defined for the endpoint which
589+
* has been deemed to be degraded.
590+
* @param payload.error - The error from the last request to the `endpointUrl`
591+
* which determined the degraded status (or `undefined` if the request was
592+
* merely slow).
480593
*/
481-
export type NetworkControllerRpcEndpointRequestRetriedEvent = {
482-
type: 'NetworkController:rpcEndpointRequestRetried';
594+
export type NetworkControllerRpcEndpointInstanceDegradedEvent = {
595+
type: 'NetworkController:rpcEndpointInstanceDegraded';
483596
payload: [
484597
{
598+
chainId: Hex;
485599
endpointUrl: string;
600+
error: unknown;
601+
networkClientId: NetworkClientId;
602+
primaryEndpointUrl: string;
603+
},
604+
];
605+
};
606+
607+
/**
608+
* `NetworkController:rpcEndpointAvailable` is published in either of the
609+
* following two cases:
610+
*
611+
* 1. The first time that a 2xx request is made to any of the designated URLs of
612+
* an RPC endpoint.
613+
* 2. When requests to any of the URLs previously failed (placing the endpoint
614+
* in a degraded or unavailable status), but are now succeeding again.
615+
*
616+
* @param payload - The event payload.
617+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
618+
* lives.
619+
* @param payload.networkClientId - The ID of the network client representing
620+
* the RPC endpoint.
621+
* @param payload.primaryEndpointUrl - The primary URL of the RPC endpoint.
622+
* @param payload.endpointUrl - The specific URL that returned a successful
623+
* response.
624+
*/
625+
export type NetworkControllerRpcEndpointAvailableEvent = {
626+
type: 'NetworkController:rpcEndpointAvailable';
627+
payload: [
628+
{
629+
chainId: Hex;
630+
endpointUrl: string;
631+
networkClientId: NetworkClientId;
632+
primaryEndpointUrl: string;
633+
},
634+
];
635+
};
636+
637+
/**
638+
* `NetworkController:rpcEndpointInstanceRetried` is published before a
639+
* request to any of the designated URLs of an RPC endpoint is retried.
640+
*
641+
* This is mainly useful for tests.
642+
*
643+
* @param payload - The event payload.
644+
* @param payload.chainId - The chain ID of the network where the RPC endpoint
645+
* lives.
646+
* @param payload.networkClientId - The ID of the network client representing
647+
* the RPC endpoint.
648+
* @param payload.primaryEndpointUrl - The primary URL of the RPC endpoint.
649+
* @param payload.endpointUrl - The URL defined for the endpoint that is being
650+
* retried.
651+
* @param payload.attempt - The current attempt counter for the endpoint URL
652+
* (starting from 0).
653+
* @see {@link RpcService} for the list of retriable errors.
654+
*/
655+
export type NetworkControllerRpcEndpointInstanceRetriedEvent = {
656+
type: 'NetworkController:rpcEndpointInstanceRetried';
657+
payload: [
658+
{
486659
attempt: number;
660+
chainId: Hex;
661+
endpointUrl: string;
662+
networkClientId: NetworkClientId;
663+
primaryEndpointUrl: string;
487664
},
488665
];
489666
};
@@ -497,8 +674,11 @@ export type NetworkControllerEvents =
497674
| NetworkControllerNetworkAddedEvent
498675
| NetworkControllerNetworkRemovedEvent
499676
| NetworkControllerRpcEndpointUnavailableEvent
677+
| NetworkControllerRpcEndpointInstanceUnavailableEvent
500678
| NetworkControllerRpcEndpointDegradedEvent
501-
| NetworkControllerRpcEndpointRequestRetriedEvent;
679+
| NetworkControllerRpcEndpointInstanceDegradedEvent
680+
| NetworkControllerRpcEndpointAvailableEvent
681+
| NetworkControllerRpcEndpointInstanceRetriedEvent;
502682

503683
/**
504684
* All events that {@link NetworkController} calls internally.
@@ -2800,6 +2980,7 @@ export class NetworkController extends BaseController<
28002980
autoManagedNetworkClientRegistry[NetworkClientType.Infura][
28012981
addedRpcEndpoint.networkClientId
28022982
] = createAutoManagedNetworkClient({
2983+
networkClientId: addedRpcEndpoint.networkClientId,
28032984
networkClientConfiguration: {
28042985
type: NetworkClientType.Infura,
28052986
chainId: networkFields.chainId,
@@ -2818,6 +2999,7 @@ export class NetworkController extends BaseController<
28182999
autoManagedNetworkClientRegistry[NetworkClientType.Custom][
28193000
addedRpcEndpoint.networkClientId
28203001
] = createAutoManagedNetworkClient({
3002+
networkClientId: addedRpcEndpoint.networkClientId,
28213003
networkClientConfiguration: {
28223004
type: NetworkClientType.Custom,
28233005
chainId: networkFields.chainId,
@@ -2980,6 +3162,7 @@ export class NetworkController extends BaseController<
29803162
return [
29813163
rpcEndpoint.networkClientId,
29823164
createAutoManagedNetworkClient({
3165+
networkClientId: rpcEndpoint.networkClientId,
29833166
networkClientConfiguration: {
29843167
type: NetworkClientType.Infura,
29853168
network: infuraNetworkName,
@@ -2999,6 +3182,7 @@ export class NetworkController extends BaseController<
29993182
return [
30003183
rpcEndpoint.networkClientId,
30013184
createAutoManagedNetworkClient({
3185+
networkClientId: rpcEndpoint.networkClientId,
30023186
networkClientConfiguration: {
30033187
type: NetworkClientType.Custom,
30043188
chainId: networkConfiguration.chainId,

0 commit comments

Comments
 (0)