Get your own Node server
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);
});

              
Test server running at http://127.0.0.1:12345
Using a custom HTTP agent with keep-alive enabled

=== Initial Agent Status ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 0
Free Sockets: 0
Pending Requests: 0

=== Making 3 concurrent requests ===
Request 1 completed with status: 200
  Response: Hello from test server!
  Connection: keep-alive

=== After Request 1 ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 1
Free Sockets: 0
Pending Requests: 0

Request 2 completed with status: 200
  Response: Hello from test server!
  Connection: keep-alive

=== After Request 2 ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 2
Free Sockets: 0
Pending Requests: 0

Request 3 completed with status: 200
  Response: Hello from test server!
  Connection: keep-alive

=== After Request 3 ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 3
Free Sockets: 0
Pending Requests: 0

=== Final Agent Status ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 0
Free Sockets: 2
Pending Requests: 0

Waiting for sockets to be moved to free pool...

=== After Idle Time ===
Max Sockets: 5
Max Free Sockets: 2
Keep Alive: true
Active Sockets: 0
Free Sockets: 2
Pending Requests: 0

=== Demo complete ===
The test server has been stopped.
The custom agent has been destroyed.