Skip to content

Commit

Permalink
(client): fixed ECONNRESET error when using http/https client
Browse files Browse the repository at this point in the history
  • Loading branch information
fenying committed Dec 6, 2023
1 parent e604683 commit 8600f43
Show file tree
Hide file tree
Showing 43 changed files with 190 additions and 59 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes Logs

## v0.4.8

- fix(client): fixed `ECONNRESET` error when using `http/https` client.

## v0.4.7

- fix(server): refuse malformed request body.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@litert/televoke",
"version": "0.4.7",
"version": "0.4.8",
"description": "A simple RPC service framework.",
"main": "lib/index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/Decoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/Encoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/Http/API.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/Http/Client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/Http/Server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/TCP/API.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/TCP/Client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/benchmarks/TCP/Server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
57 changes: 55 additions & 2 deletions src/examples/Http.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -93,7 +93,7 @@ interface IGa extends $Televoke.IServiceAPIs {
const client = $Televoke.createHttpClient<IGa>({
host: '127.0.0.1',
port: 8899,
ridGenerator: $Televoke.createIncreasementRIDGenerator(0)
ridGenerator: $Televoke.createIncrementRIDGenerator(0)
});

server.setRouter(router);
Expand Down Expand Up @@ -128,6 +128,59 @@ interface IGa extends $Televoke.IServiceAPIs {

console.log(await requestByHttp('PUT', '{"fffff":', {}));

try {

await client.invoke('hi', {'name': 'Mick'});
const T = Date.now();

while (1) {

if (T < Date.now() - 10000) {

break;
}
}

console.log(await client.invoke('hi', {'name': 'Mick'}));

console.info('Failed: Should got ECONNRESET here.');
}
catch (e) {

console.error('PASSED: Got ECONNRESET here when CPU stuck for 10s');
console.error(e);
}

const client2 = $Televoke.createHttpClient<IGa>({
host: '127.0.0.1',
port: 8899,
ridGenerator: $Televoke.createIncrementRIDGenerator(0),
retryConnReset: true,
});

try {

await client2.invoke('hi', {'name': 'Mick'});
const T = Date.now();

while (1) {

if (T < Date.now() - 10000) {

break;
}
}

console.log(await client2.invoke('hi', {'name': 'Mick'}));

console.info('PASSED: No ECONNRESET here even if CPU stuck for 10s');
}
catch (e) {

console.error('Failed: Still got error here.');
console.error(e);
}

await server.close();

})().catch(console.error);
4 changes: 2 additions & 2 deletions src/examples/Https.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,7 +36,7 @@ interface IGa extends $Televoke.IServiceAPIs {

const client = $Televoke.createHttpsClient<IGa>({
host: 'examples.org',
ridGenerator: $Televoke.createIncreasementRIDGenerator(0),
ridGenerator: $Televoke.createIncrementRIDGenerator(0),
path: '/path/to/rpc/entry'
});

Expand Down
2 changes: 1 addition & 1 deletion src/examples/TCP.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Client/BuiltInRIDGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as C from './Common';

export function createIncreasementRIDGenerator(base: number): C.IRIDGenerator {
export function createIncrementRIDGenerator(base: number): C.IRIDGenerator {

return () => base++;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Client/Common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Client/Errors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
53 changes: 45 additions & 8 deletions src/lib/Client/HttpClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,26 +33,55 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
private readonly _ridGenerator: C.IRIDGenerator,
private readonly _path: string = '/',
private readonly _timeout: number = 30000,
private readonly _apiNameWrapper?: (name: string) => string
private readonly _apiNameWrapper?: (name: string) => string,
private readonly _retryConnReset?: boolean,
) {

super();

this._agent = new $Http.Agent({
maxSockets: 0,
keepAlive: true,
keepAliveMsecs: 30000
keepAliveMsecs: this._timeout
});
}

public invoke(api: any, ...args: any[]): Promise<any> {
public async invoke(api: any, ...args: any[]): Promise<any> {

return this._call(api, false, args);
try {

return await this._call(api, false, args);
}
catch (e) {

if (this._retryConnReset && (e as any)?.code === 'ECONNRESET') {

return this._call(api, false, args);
}
else {

throw e;
}
}
}

public call(api: any, ...args: any[]): Promise<any> {
public async call(api: any, ...args: any[]): Promise<any> {

try {

return await this._call(api, true, args);
}
catch (e) {

return this._call(api, true, args);
if (this._retryConnReset && (e as any)?.code === 'ECONNRESET') {

return this._call(api, true, args);
}
else {

throw e;
}
}
}

private _call(api: any, returnRaw: boolean, args: any[]): Promise<any> {
Expand Down Expand Up @@ -217,6 +246,13 @@ export interface IHttpClientOptions {
timeout?: number;

apiNameWrapper?: (name: string) => string;

/**
* Whether to retry when the connection is reset.
*
* @default false
*/
retryConnReset?: boolean;
}

export function createHttpClient<TAPIs extends G.IServiceAPIs>(opts: IHttpClientOptions): C.IClient<TAPIs> {
Expand All @@ -227,6 +263,7 @@ export function createHttpClient<TAPIs extends G.IServiceAPIs>(opts: IHttpClient
opts.ridGenerator,
opts.path,
opts.timeout,
opts.apiNameWrapper
opts.apiNameWrapper,
opts.retryConnReset,
);
}
53 changes: 45 additions & 8 deletions src/lib/Client/HttpsClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2021 Angus.Fenying <fenying@litert.org>
* Copyright 2023 Angus.Fenying <fenying@litert.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -34,28 +34,57 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
private readonly _path: string = '',
private readonly _timeout: number = 30000,
private readonly _apiNameWrapper?: (name: string) => string,
tlsAgentOptions?: $Https.AgentOptions
tlsAgentOptions?: $Https.AgentOptions,
private readonly _retryConnReset?: boolean,
) {

super();

this._agent = new $Https.Agent({
maxSockets: 0,
keepAlive: true,
keepAliveMsecs: 30000,
keepAliveMsecs: this._timeout,
// servername: _host,
...tlsAgentOptions
});
}

public invoke(api: any, ...args: any[]): Promise<any> {
public async invoke(api: any, ...args: any[]): Promise<any> {

return this._call(api, false, args);
try {

return await this._call(api, false, args);
}
catch (e) {

if (this._retryConnReset && (e as any)?.code === 'ECONNRESET') {

return this._call(api, false, args);
}
else {

throw e;
}
}
}

public call(api: any, ...args: any[]): Promise<any> {
public async call(api: any, ...args: any[]): Promise<any> {

try {

return await this._call(api, true, args);
}
catch (e) {

return this._call(api, true, args);
if (this._retryConnReset && (e as any)?.code === 'ECONNRESET') {

return this._call(api, true, args);
}
else {

throw e;
}
}
}

private _call(api: any, returnRaw: boolean, args: any[]): Promise<any> {
Expand Down Expand Up @@ -222,6 +251,13 @@ export interface IHttpsClientOptions {
apiNameWrapper?: (name: string) => string;

tlsAgentOptions?: $Https.AgentOptions;

/**
* Whether to retry when the connection is reset.
*
* @default false
*/
retryConnReset?: boolean;
}

export function createHttpsClient<TAPIs extends G.IServiceAPIs>(opts: IHttpsClientOptions): C.IClient<TAPIs> {
Expand All @@ -233,6 +269,7 @@ export function createHttpsClient<TAPIs extends G.IServiceAPIs>(opts: IHttpsClie
opts.path,
opts.timeout,
opts.apiNameWrapper,
opts.tlsAgentOptions
opts.tlsAgentOptions,
opts.retryConnReset,
);
}
Loading

0 comments on commit 8600f43

Please sign in to comment.