const http = require('http');
const { once } = require('events');
// Create a simple HTTP server for testing
const server = http.createServer((req, res) => {
// Add a small delay to simulate network latency
setTimeout(() => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: 'Hello from test server!',
timestamp: new Date().toISOString(),
connection: req.headers.connection || 'close'
}));
}, 100);
});
// Create a custom agent with specific options
const customAgent = new http.Agent({
keepAlive: true, // Enable keep-alive for persistent connections
keepAliveMsecs: 1000, // Time to wait before sending TCP KeepAlive packet
maxSockets: 5, // Maximum number of sockets per host
maxFreeSockets: 2, // Maximum number of free sockets to keep open
timeout: 30000, // Socket timeout in milliseconds
scheduling: 'fifo' // Use FIFO scheduling (instead of LIFO)
});
// Helper function to make a request using the custom agent
function makeRequest(url, agent) {
return new Promise((resolve, reject) => {
const options = new URL(url);
const req = http.request({
hostname: options.hostname,
port: options.port,
path: options.pathname,
method: 'GET',
agent: agent
}, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
resolve({
statusCode: res.statusCode,
headers: res.headers,
body: data ? JSON.parse(data) : null
});
});
});
req.on('error', (err) => {
reject(err);
});
req.end();
});
}
// Function to display agent status
function logAgentStatus(agent, label = 'Agent Status') {
console.log(`\n=== ${label} ===`);
console.log('Max Sockets:', agent.maxSockets);
console.log('Max Free Sockets:', agent.maxFreeSockets);
console.log('Keep Alive:', agent.keepAlive);
console.log('Active Sockets:', Object.keys(agent.sockets).length);
console.log('Free Sockets:', Object.keys(agent.freeSockets).length);
console.log('Pending Requests:', Object.keys(agent.requests).length);
}
// Main function to demonstrate the custom agent
async function runDemo() {
// Start the test server
await new Promise((resolve) => {
server.listen(0, '127.0.0.1', resolve);
});
const serverAddress = server.address();
const baseUrl = `http://${serverAddress.address}:${serverAddress.port}`;
console.log(`Test server running at ${baseUrl}`);
console.log('Using a custom HTTP agent with keep-alive enabled');
// Show initial agent status
logAgentStatus(customAgent, 'Initial Agent Status');
// Make multiple concurrent requests to demonstrate connection pooling
console.log('\n=== Making 3 concurrent requests ===');
const requests = [];
for (let i = 0; i < 3; i++) {
requests.push(
makeRequest(baseUrl, customAgent)
.then((response) => {
console.log(`Request ${i + 1} completed with status: ${response.statusCode}`);
console.log(` Response: ${response.body.message}`);
console.log(` Connection: ${response.body.connection}`);
logAgentStatus(customAgent, `After Request ${i + 1}`);
})
);
}
// Wait for all requests to complete
await Promise.all(requests);
// Show final agent status
logAgentStatus(customAgent, 'Final Agent Status');
// Wait a bit to see if sockets are moved to free pool
console.log('\nWaiting for sockets to be moved to free pool...');
await new Promise(resolve => setTimeout(resolve, 1500));
// Show agent status after delay
logAgentStatus(customAgent, 'After Idle Time');
// Clean up
customAgent.destroy();
server.close();
console.log('\n=== Demo complete ===');
console.log('The test server has been stopped.');
console.log('The custom agent has been destroyed.');
}
// Run the demo and handle any errors
runDemo().catch((err) => {
console.error('Error in demo:', err);
customAgent.destroy();
server.close();
process.exit(1);
});