Skip to content

Commit 22fa407

Browse files
authored
feat: Reuse same HTTP Client Instance when possible (#340)
* reusing same http client instance Signed-off-by: Deepanshu Agarwal <[email protected]> * Fixing test Signed-off-by: Deepanshu Agarwal <[email protected]> * Update HTTPClient Signed-off-by: Deepanshu Agarwal <[email protected]> * if-else imorovement Signed-off-by: Deepanshu Agarwal <[email protected]> * Correct indentation Signed-off-by: Deepanshu Agarwal <[email protected]> Signed-off-by: Deepanshu Agarwal <[email protected]>
1 parent 46473c0 commit 22fa407

File tree

2 files changed

+27
-15
lines changed

2 files changed

+27
-15
lines changed

src/implementation/Client/HTTPClient/HTTPClient.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ import HTTPClientSidecar from "./sidecar";
2525
export default class HTTPClient implements IClient {
2626
private isInitialized: boolean;
2727

28-
private readonly client: typeof fetch;
28+
private static client: typeof fetch;
2929
private readonly clientHost: string;
3030
private readonly clientPort: string;
3131
private readonly clientUrl: string;
3232
private readonly options: DaprClientOptions;
3333
private readonly logger: Logger;
3434

35-
private readonly httpAgent;
36-
private readonly httpsAgent;
35+
private static httpAgent: http.Agent;
36+
private static httpsAgent: https.Agent;
3737

3838
constructor(
3939
host = Settings.getDefaultHost()
@@ -45,7 +45,6 @@ export default class HTTPClient implements IClient {
4545
this.options = options;
4646
this.logger = new Logger("HTTPClient", "HTTPClient", this.options.logger);
4747
this.isInitialized = false;
48-
4948
// fallback to default
5049
if (this.options.isKeepAlive === undefined) {
5150
this.options.isKeepAlive = true;
@@ -57,17 +56,21 @@ export default class HTTPClient implements IClient {
5756
this.clientUrl = `${this.clientHost}:${this.clientPort}/v1.0`;
5857
}
5958

60-
this.client = fetch;
59+
if(!HTTPClient.client) {
60+
HTTPClient.client = fetch;
61+
}
6162

6263
// Add a custom agent so we can decide if we want to reuse connections or not
6364
// we use an agent so we can reuse an open connection, limiting handshake requirements
6465
// Note: when using an agent, we will encounter TCPWRAP since the connection doesn't get destroyed
65-
if (this.options.isKeepAlive) {
66-
this.httpAgent = new http.Agent({ keepAlive: true, keepAliveMsecs: 30 * 1000 });
67-
this.httpsAgent = new https.Agent({ keepAlive: true, keepAliveMsecs: 30 * 1000 });
68-
} else {
69-
this.httpAgent = new http.Agent();
70-
this.httpsAgent = new https.Agent();
66+
const keepAlive = this.options.isKeepAlive;
67+
const keepAliveMsecs = 30 * 1000; // it is applicable only when keepAlive is set to true
68+
69+
if(!HTTPClient.httpAgent) {
70+
HTTPClient.httpAgent = new http.Agent({ keepAlive: keepAlive, keepAliveMsecs: keepAliveMsecs });
71+
}
72+
if(!HTTPClient.httpsAgent) {
73+
HTTPClient.httpsAgent = new https.Agent({ keepAlive: keepAlive, keepAliveMsecs: keepAliveMsecs });
7174
}
7275
}
7376

@@ -78,7 +81,7 @@ export default class HTTPClient implements IClient {
7881
await this.start();
7982
}
8083

81-
return this.client;
84+
return HTTPClient.client;
8285
}
8386

8487
getClientHost(): string {
@@ -114,8 +117,8 @@ export default class HTTPClient implements IClient {
114117
}
115118

116119
async stop(): Promise<void> {
117-
this.httpAgent.destroy();
118-
this.httpsAgent.destroy();
120+
HTTPClient.httpAgent.destroy();
121+
HTTPClient.httpsAgent.destroy();
119122
}
120123

121124
async start(): Promise<void> {
@@ -171,7 +174,7 @@ export default class HTTPClient implements IClient {
171174
}
172175

173176
const urlFull = url.startsWith("http") ? url : `${this.clientUrl}${url}`;
174-
const agent = urlFull.startsWith("https") ? this.httpsAgent : this.httpAgent;
177+
const agent = urlFull.startsWith("https") ? HTTPClient.httpsAgent : HTTPClient.httpAgent;
175178
params.agent = agent;
176179

177180
this.logger.debug(`Fetching ${params.method} ${urlFull} with body: (${params.body})`);

test/unit/main/DaprClient.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,13 @@ describe('DaprClient', () => {
3131
expect(msg).toEqual("DAPR_INCORRECT_SIDECAR_PORT");
3232
}
3333
});
34+
35+
it('same http client should be returned for multiple DaprClient invocations', () => {
36+
const daprClient1 = new DaprClient(host, port);
37+
const daprClient2 = new DaprClient(host, port);
38+
return Promise.all([daprClient1.getDaprClient().getClient(false),
39+
daprClient2.getDaprClient().getClient(false)]).then(function(values) {
40+
expect(values[0]).toEqual(values[1]);
41+
});
42+
});
3443
});

0 commit comments

Comments
 (0)