From 3606a4a939ca1702d5e1b4d524dc77377ac0f962 Mon Sep 17 00:00:00 2001 From: zhangyouxin Date: Wed, 29 Mar 2023 08:31:37 +0800 Subject: [PATCH 1/2] refactor: exrtact request with timeout and retry as a stateless function --- .../ownership/backend/backendUtils.ts | 28 +++-------------- .../src/services/ownership/backend/request.ts | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 packages/extension-chrome/src/services/ownership/backend/request.ts diff --git a/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts b/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts index 8ad0145c..b0243b92 100644 --- a/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts +++ b/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts @@ -3,9 +3,8 @@ import { asserts } from '@nexus-wallet/utils'; import { ScriptConfig } from '@ckb-lumos/config-manager'; import { JSONRPCRequest, JSONRPCResponse } from 'json-rpc-2.0'; import { RPC as RpcType } from '@ckb-lumos/rpc/lib/types/rpc'; +import { RequestOptions, requestWithOptions } from './request'; import { NexusCommonErrors } from '../../../errors'; -import pTimeout from './thirdpartyLib/p-timeout'; -import pRetry from './thirdpartyLib/p-retry'; type Order = 'asc' | 'desc'; type Limit = HexNumber; @@ -91,39 +90,22 @@ type RpcClient = { batchRequest: (method: string, batchParams: Params[]) => Promise; }; -type RpcClientOptions = { - timeout?: number; // in milliseconds - maxRetries?: number; -}; - -function createRpcClient(url: string, options?: RpcClientOptions): RpcClient { +function createRpcClient(url: string, options?: RequestOptions): RpcClient { // auto-increment id let jsonRpcId = 0; async function _request(body: JSONRPCRequest | JSONRPCRequest[]): Promise { ++jsonRpcId; - const retryRunner = async () => { - const res = await fetch(url, { + const fetchProvider = () => + fetch(url, { method: 'POST', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', }, }); - // Abort retrying if the resource doesn't exist - if (res.status >= 300) { - /* istanbul ignore next */ - throw NexusCommonErrors.RequestCkbFailed(res); - } - return res.json(); - }; - - const retryPromise = pRetry(retryRunner, { retries: options?.maxRetries || 5 }); - const res = await pTimeout(retryPromise, { - milliseconds: options?.timeout || 5_000, - }); - return res as Promise; + return requestWithOptions(fetchProvider, options); } async function request(method: string, params: Params): Promise { diff --git a/packages/extension-chrome/src/services/ownership/backend/request.ts b/packages/extension-chrome/src/services/ownership/backend/request.ts new file mode 100644 index 00000000..58513c35 --- /dev/null +++ b/packages/extension-chrome/src/services/ownership/backend/request.ts @@ -0,0 +1,31 @@ +import { JSONRPCResponse } from 'json-rpc-2.0'; +import { NexusCommonErrors } from '../../../errors'; +import pRetry from './thirdpartyLib/p-retry'; +import pTimeout from './thirdpartyLib/p-timeout'; + +export type RequestOptions = { + timeout?: number; // in milliseconds + maxRetries?: number; +}; + +export const requestWithOptions = async ( + promiseCtor: () => Promise, + options?: RequestOptions, +): Promise => { + const retryRunner = async () => { + const res = await promiseCtor(); + // Abort retrying if the resource doesn't exist + if (res.status >= 300) { + /* istanbul ignore next */ + throw NexusCommonErrors.RequestCkbFailed(res); + } + return res.json(); + }; + + const retryPromise = pRetry(retryRunner, { retries: options?.maxRetries || 5 }); + const res = await pTimeout(retryPromise, { + milliseconds: options?.timeout || 5_000, + }); + + return res as Promise; +}; From 0e4f3d4b823f68ca16ae87190c50aec68af1e11f Mon Sep 17 00:00:00 2001 From: zhangyouxin Date: Wed, 29 Mar 2023 08:39:17 +0800 Subject: [PATCH 2/2] refactor: change test case to cover request --- .../ownership/backend/{backendUtil.test.ts => request.ts} | 6 ++---- .../src/services/ownership/backend/backendUtils.ts | 4 ++-- .../src/services/ownership/backend/request.ts | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) rename packages/extension-chrome/__tests__/services/ownership/backend/{backendUtil.test.ts => request.ts} (70%) diff --git a/packages/extension-chrome/__tests__/services/ownership/backend/backendUtil.test.ts b/packages/extension-chrome/__tests__/services/ownership/backend/request.ts similarity index 70% rename from packages/extension-chrome/__tests__/services/ownership/backend/backendUtil.test.ts rename to packages/extension-chrome/__tests__/services/ownership/backend/request.ts index 17a7efc1..4f68ec67 100644 --- a/packages/extension-chrome/__tests__/services/ownership/backend/backendUtil.test.ts +++ b/packages/extension-chrome/__tests__/services/ownership/backend/request.ts @@ -1,5 +1,5 @@ import fetchMock from 'jest-fetch-mock'; -import { createRpcClient } from '../../../../src/services/ownership/backend/backendUtils'; +import { requestWithRetries } from '../../../../src/services/ownership/backend/request'; describe('refetch', () => { beforeAll(() => { @@ -11,9 +11,7 @@ describe('refetch', () => { it('should refetch when first request fails', async () => { fetchMock.mockRejectOnce(new Error('some error')); fetchMock.mockResponse(JSON.stringify({ result: 'some result' })); - const { request } = createRpcClient(''); - await request('some_method', {}); - + await requestWithRetries(() => fetch('http://dummy')); expect(fetch).toBeCalledTimes(2); }); }); diff --git a/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts b/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts index b0243b92..7e760cce 100644 --- a/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts +++ b/packages/extension-chrome/src/services/ownership/backend/backendUtils.ts @@ -3,7 +3,7 @@ import { asserts } from '@nexus-wallet/utils'; import { ScriptConfig } from '@ckb-lumos/config-manager'; import { JSONRPCRequest, JSONRPCResponse } from 'json-rpc-2.0'; import { RPC as RpcType } from '@ckb-lumos/rpc/lib/types/rpc'; -import { RequestOptions, requestWithOptions } from './request'; +import { RequestOptions, requestWithRetries } from './request'; import { NexusCommonErrors } from '../../../errors'; type Order = 'asc' | 'desc'; @@ -105,7 +105,7 @@ function createRpcClient(url: string, options?: RequestOptions): RpcClient { }, }); - return requestWithOptions(fetchProvider, options); + return requestWithRetries(fetchProvider, options); } async function request(method: string, params: Params): Promise { diff --git a/packages/extension-chrome/src/services/ownership/backend/request.ts b/packages/extension-chrome/src/services/ownership/backend/request.ts index 58513c35..a58a8961 100644 --- a/packages/extension-chrome/src/services/ownership/backend/request.ts +++ b/packages/extension-chrome/src/services/ownership/backend/request.ts @@ -8,7 +8,7 @@ export type RequestOptions = { maxRetries?: number; }; -export const requestWithOptions = async ( +export const requestWithRetries = async ( promiseCtor: () => Promise, options?: RequestOptions, ): Promise => {