Node.js Microservice Architecture Connection pooling with Axios and agentkeepalive
Node.js Part 14 May 25, 2022
If you are using plain Axios, then with each request a new connection is opened. However, the server your application is running on can only handle a limited number of connections at the same time. If no new connections can be created, then this can lead to all sort of weird errors in production. Let's avoid this and use a connection pool.
Luckily, there is an npm package agentkeepalive
that implements the concept of a connection pool.
npm install agentkeepalive --save
We only need to configure axios
to use this package agentkeepalive
.
HTTP Agents 🔗
In a module src/http/create-http-agents.ts
, we specify an HTTP agent and an HTTPS agent. The configuration depends on your production environment and requirements on the service. You might want to play around with different settings.
import Agent from "agentkeepalive";
export function createHttpAgent() {
return new Agent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000,
freeSocketTimeout: 30000,
});
}
export function createHttpsAgent() {
return new Agent.HttpsAgent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000,
freeSocketTimeout: 30000,
});
}
Connecting Axios and agentkeepalive 🔗
In the same directory src/http
, we create a module configure-http.ts
. It contains a function that registers the HTTP agents on the global axios
object.
import axios from "axios";
import { createHttpAgent, createHttpsAgent } from "./create-http-agents";
export function configureHttp(): void {
axios.defaults.httpAgent = createHttpAgent();
axios.defaults.httpsAgent = createHttpsAgent();
}
If the function configureHttp
has been called, then all requests made with the global object axios
use the connection pool.
import axios from "axios";
import { config } from "../../configuration/config";
export function sendNotification(message: string): Promise<void> {
return axios.post(`${config.http.servicesUrl}/notify/notifications`, {
message,
});
}
Configuring Axios on application start 🔗
Now, we only need to make sure the function is called when the application starts. We do this as one of the first steps in the function main
in the module src/main.ts
.
import app from "./app";
import * as http from "http";
import { logger } from "./logger";
import { configureHttp } from "./http/configure-http";
async function main(_args: string[]) {
const port = process.env.PORT ?? 3000;
configureHttp();
const server = http.createServer(app);
server.listen(port, () => {
logger.info(`Server listening on port ${port}!`);
});
}
main(process.argv).catch((error) => {
// ...
});
// ...
Conclusion 🔗
We configured a connection pool with Axios. Every outgoing HTTP request done with the global axios
object now utilizes a connection from the connection pool.
Become a GitHub sponsor to access the code of this post as a GitHub repo.