-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: close the server after in-flight requests complete #25
fix: close the server after in-flight requests complete #25
Conversation
Currently, if there are any requests in flight when `terminator.terminate` is called, `terminate` will wait for `gracefulTerminationTimeout` milliseconds, even if all in-flight requests complete before that timeout. This updates the termination logic in `createInternalHttpTerminator` to close the server as soon as there are no requests in flight; for example, if the timeout is set to 15000ms but all in-flight requests are complete after 1000ms, `terminate` will return after ~1000ms. Fixes gajus#16.
await waitFor(() => { | ||
return sockets.size === 0 && secureSockets.size === 0; | ||
}, { | ||
interval: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that p-wait-for
polls for this condition every 1ms. This feels a little janky to me, but was the most straightforward solution I could think of (and clearly represents an improvement over the current behavior). Open to alternative suggestions if this also feels gross to you.
@ndhoule, @danielrearden suggested a possibly better implementation. What do you think? let resolveSocketsClosed;
const socketsClosed = new Promise((resolve) => {
resolveSocketsClosed = resolve;
server.on('connection', (socket) => {
if (terminating) {
socket.destroy();
} else {
sockets.add(socket);
socket.once('close', () => {
sockets.delete(socket);
if (terminating && !sockets.size && !secureSockets.size) {
resolve();
}
});
}
});
server.on('secureConnection', (socket) => {
if (terminating) {
socket.destroy();
} else {
secureSockets.add(socket);
socket.once('close', () => {
secureSockets.delete(socket);
if (terminating && !sockets.size && !secureSockets.size) {
resolve();
}
});
}
});
}); Then inside terminate if (!sockets.size && !secureSockets.size) {
resolveSocketsClosed()
}
await socketsClosed That should prevent the Promise from hanging around if there were no sockets to start with. |
@gajus The advantages of the alternative implementation aren't completely obvious; would you mind explaining? (Is it that it avoids polling during termination?) The alternative seems reasonable to me, though the main tradeoff I see is that the promise resolution logic is a bit more complex to reason about. |
Correct. |
The strategy of |
Can we reduce the polling to something more reasonable, like every 10 milliseconds? Otherwise, Okey to merge. |
I would also like to see this behavior fixed as the docs are currently misleading. Since it seemed like there was some discussion around which approach was preferred, I created a different alternative approach to consider. If you like it, I can put up a PR. I adapted the test @ndhoule added in this PR. I found the |
Any updates from @ndhoule ? This proposed solution would solve a need, but just wondering if I need to roll with my own solution or wait on this. Happy to offer some help if there is any pending work. |
🎉 This PR is included in version 3.0.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Currently, if there are any requests in flight when
terminator.terminate
is called,terminate
will wait forgracefulTerminationTimeout
milliseconds, even if all in-flight requests complete before that timeout.This updates the termination logic in
createInternalHttpTerminator
to close the server as soon as there are no requests in flight; for example, if the timeout is set to 15000ms but all in-flight requests are complete after 1000ms,terminate
will return after ~1000ms.Fixes #16.
PS: Thanks for maintaining this project! I was led here by of issues with other packages that's pretty much identical to the list in your README.