Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include endpointUrl in RpcService event listener data #5225

Merged
merged 2 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/controller-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add utility function for reducing boilerplate for service classes ([#5154](https://github.com/MetaMask/core/pull/5154), [#5143](https://github.com/MetaMask/core/pull/5143), [#5149](https://github.com/MetaMask/core/pull/5149), [#5188](https://github.com/MetaMask/core/pull/5188), [#5192](https://github.com/MetaMask/core/pull/5192))
- Add utility function for reducing boilerplate for service classes ([#5154](https://github.com/MetaMask/core/pull/5154), [#5143](https://github.com/MetaMask/core/pull/5143), [#5149](https://github.com/MetaMask/core/pull/5149), [#5188](https://github.com/MetaMask/core/pull/5188), [#5192](https://github.com/MetaMask/core/pull/5192), [#5225](https://github.com/MetaMask/core/pull/5225))
- Add function `createServicePolicy`
- Add constants `DEFAULT_CIRCUIT_BREAK_DURATION`, `DEFAULT_DEGRADED_THRESHOLD`, `DEFAULT_MAX_CONSECUTIVE_FAILURES`, and `DEFAULT_MAX_RETRIES`
- Add types `ServicePolicy` and `CreateServicePolicyOptions`
- Re-export `BrokenCircuitError`, `CircuitState`, `handleAll`, and `handleWhen` from `cockatiel`
- Export `CockatielEvent` type which is an alias of the `Event` type from `cockatiel`

## [11.4.5]

Expand Down
2 changes: 1 addition & 1 deletion packages/controller-utils/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = merge(baseConfig, {
coverageThreshold: {
global: {
branches: 78.12,
functions: 80.7,
functions: 80.35,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've checked the coverage report and all of the lines I added are tested.

lines: 87.3,
statements: 86.5,
},
Expand Down
20 changes: 9 additions & 11 deletions packages/controller-utils/src/create-service-policy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
BrokenCircuitError,
CircuitState,
EventEmitter as CockatielEventEmitter,
ConsecutiveBreaker,
ExponentialBackoff,
circuitBreaker,
Expand All @@ -11,13 +12,16 @@ import {
} from 'cockatiel';
import type {
CircuitBreakerPolicy,
Event as CockatielEvent,
IPolicy,
Policy,
RetryPolicy,
} from 'cockatiel';

export { CircuitState, BrokenCircuitError, handleAll, handleWhen };

export type { CockatielEvent };

/**
* The options for `createServicePolicy`.
*/
Expand Down Expand Up @@ -76,7 +80,7 @@ export type ServicePolicy = IPolicy & {
* never succeeds before the retry policy gives up and before the maximum
* number of consecutive failures has been reached.
*/
onDegraded: (fn: () => void) => void;
onDegraded: CockatielEvent<void>;
/**
* A function which will be called by the retry policy each time the service
* fails and the policy kicks off a timer to re-run the service. This is
Expand Down Expand Up @@ -203,27 +207,21 @@ export function createServicePolicy({
});
const onBreak = circuitBreakerPolicy.onBreak.bind(circuitBreakerPolicy);

const onDegradedListeners: (() => void)[] = [];
const onDegradedEventEmitter = new CockatielEventEmitter<void>();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here we are reusing the Cockatiel built-in EventEmitter class instead of implementing the EventEmitter pattern ourselves. We do this because we want the signature of the onDegraded method to match the signatures for onRetry and onBreak (onDegraded is a custom hook we add, whereas onRetry and onBreak essentially come directly from Cockatiel).

retryPolicy.onGiveUp(() => {
if (circuitBreakerPolicy.state === CircuitState.Closed) {
for (const listener of onDegradedListeners) {
listener();
}
onDegradedEventEmitter.emit();
}
});
retryPolicy.onSuccess(({ duration }) => {
if (
circuitBreakerPolicy.state === CircuitState.Closed &&
duration > degradedThreshold
) {
for (const listener of onDegradedListeners) {
listener();
}
onDegradedEventEmitter.emit();
}
});
const onDegraded = (listener: () => void) => {
onDegradedListeners.push(listener);
};
const onDegraded = onDegradedEventEmitter.addListener;

// Every time the retry policy makes an attempt, it executes the circuit
// breaker policy, which executes the service.
Expand Down
1 change: 1 addition & 0 deletions packages/controller-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export {
handleWhen,
} from './create-service-policy';
export type {
CockatielEvent,
CreateServicePolicyOptions,
ServicePolicy,
} from './create-service-policy';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,60 @@ import type {
JsonRpcResponse,
} from '@metamask/utils';

import type { FetchOptions } from './shared';
import type { AddToCockatielEventData, FetchOptions } from './shared';

/**
* The interface for a service class responsible for making a request to an RPC
* endpoint.
*/
export type AbstractRpcService = Partial<
Pick<ServicePolicy, 'onBreak' | 'onRetry' | 'onDegraded'>
> & {
export type AbstractRpcService = {
/**
* Listens for when the RPC service retries the request.
*
* @param listener - The callback to be called when the retry occurs.
* @returns What {@link ServicePolicy.onRetry} returns.
* @see {@link createServicePolicy}
*/
onRetry(
listener: AddToCockatielEventData<
Parameters<ServicePolicy['onRetry']>[0],
{ endpointUrl: string }
>,
): ReturnType<ServicePolicy['onRetry']>;

/**
* Listens for when the RPC service retries the request too many times in a
* row.
*
* @param listener - The callback to be called when the circuit is broken.
* @returns What {@link ServicePolicy.onBreak} returns.
* @see {@link createServicePolicy}
*/
onBreak(
listener: AddToCockatielEventData<
Parameters<ServicePolicy['onBreak']>[0],
{ endpointUrl: string }
>,
): ReturnType<ServicePolicy['onBreak']>;

/**
* Listens for when the policy underlying this RPC service detects a slow
* request.
*
* @param listener - The callback to be called when the request is slow.
* @returns What {@link ServicePolicy.onDegraded} returns.
* @see {@link createServicePolicy}
*/
onDegraded(
listener: AddToCockatielEventData<
Parameters<ServicePolicy['onDegraded']>[0],
{ endpointUrl: string }
>,
): ReturnType<ServicePolicy['onDegraded']>;

/**
* Makes a request to the RPC endpoint.
*/
request<Params extends JsonRpcParams, Result extends Json>(
jsonRpcRequest: JsonRpcRequest<Params>,
fetchOptions?: FetchOptions,
Expand Down
Loading
Loading