Skip to content

Instantly share code, notes, and snippets.

@Ethan-Arrowood
Last active July 15, 2025 21:04
Show Gist options
  • Select an option

  • Save Ethan-Arrowood/e03b163eaf58a1b847bf8e0aacb94cd6 to your computer and use it in GitHub Desktop.

Select an option

Save Ethan-Arrowood/e03b163eaf58a1b847bf8e0aacb94cd6 to your computer and use it in GitHub Desktop.
A simplified example of Undici properly terminating connection when a FIN packet is forcibly sent
import { createServer } from 'node:http';
import { Client } from 'undici';
const server = createServer(
{ keepAlive: true, keepAliveTimeout: 20 * 1000 },
(req, res) => {
res.writeHead(200, {
'Content-Type': 'text/plain',
connection: 'keep-alive',
'keep-alive': 'timeout=20',
});
// Send FIN packet randomly between 5 and 15 seconds
setTimeout(
() => {
clearInterval(dataInternal);
req.socket.end(() => {
console.log('Socket closed after sending FIN');
});
},
Math.random() * (15000 - 5000) + 5000,
);
// Write some data every second
let c = 0;
const dataInternal = setInterval(() => {
res.write(`data ${c++}\n`);
}, 1000);
},
);
server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`, {
keepAliveTimeout: 20 * 1000,
});
client.on('connect', () => {
console.log('Client connected to server');
});
client.on('disconnect', () => {
console.log('Client disconnected from server');
});
setTimeout(() => {
console.log('20 (keep-alive) - 1 seconds has passed!');
console.log('client stats', client.stats);
server.close();
}, 19 * 1000);
client.request(
{
path: '/',
method: 'GET',
},
(error, response) => {
console.log('client stats', client.stats);
if (error) {
console.error('Request failed:', error);
return;
}
response.body.on('data', (chunk) => {
console.log('Received chunk:', chunk.toString());
});
response.body.on('error', (err) => {
console.error('Response body error:', err.message);
});
response.body.on('end', () => {
console.log('Response ended');
});
},
);
});
@Ethan-Arrowood
Copy link
Author

Ethan-Arrowood commented Jul 15, 2025

Example run:

Client connected to server
client stats ClientStats { connected: true, pending: 0, running: 1, size: 1 }
Received chunk: data 0

Received chunk: data 1

Received chunk: data 2

Received chunk: data 3

Received chunk: data 4

Received chunk: data 5

Received chunk: data 6

Received chunk: data 7

Received chunk: data 8

Received chunk: data 9

Received chunk: data 10

Received chunk: data 11

Received chunk: data 12

Socket closed after sending FIN
Client disconnected from server
Response body error: other side closed
20 (keep-alive) - 1 seconds has passed!
client stats ClientStats { connected: false, pending: 0, running: 0, size: 0 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment