-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Make HTTP server shutdown more graceful #6719
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
Conversation
Possible attack vector by denying the service the ability to shut down / restart by keeping a connection open? |
|
After Note that this solution is cleaner in any case, it doesn't rule out queuing a |
|
utACK. I agree that the attack vectors are out of scope for this PR maybe for the whole http-json-rpc-daemon (it's not hardened enough to expose to potential malicious environments). |
|
utACK, just thought I'd mention it. |
|
@dcousens It's great that you mentioned it. It reminded me of potential issue of this: what happens if a timer is stilll running, will it block the event queue exit until it triggers? Pushed another related fix: http: Wait for worker threads to exitAdd a WaitExit() call to http's WorkQueue to make StopHTTPServer delete the work queue only when all worker threads stopped. This fixes a problem that was reproducable by pressing Ctrl-C during AppInit2: I was assuming that |
049587c to
bfc9707
Compare
|
Pushed another commit to force-exit the event loop after a predefined time after interruption. This addresses @dcousens 's issue, as well as the case that other events are still lingering (such as a wallet unlock timer). |
|
utACK, well done @laanwj |
|
Concept ACK, btw. Definitely an improvement. |
Shutting down the HTTP server currently breaks off all current requests. This can create a race condition with RPC `stop` command, where the calling process never receives confirmation. This change removes the listening sockets on shutdown so that no new requests can come in, but no longer breaks off requests in progress. Meant to fix bitcoin#6717.
Add a WaitExit() call to http's WorkQueue to make it delete the work queue only when all worker threads stopped. This fixes a problem that was reproducable by pressing Ctrl-C during AppInit2: ``` /usr/include/boost/thread/pthread/condition_variable_fwd.hpp:81: boost::condition_variable::~condition_variable(): Assertion `!ret' failed. /usr/include/boost/thread/pthread/mutex.hpp:108: boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed. ``` I was assuming that `threadGroup->join_all();` would always have been called when entering the Shutdown(). However this is not the case in bitcoind's AppInit2-non-zero-exit case "was left out intentionally here".
This makes sure that the event loop eventually terminates, even if an event (like an open timeout, or a hanging connection) happens to be holding it up.
48c8a95 to
ec908d5
Compare
|
Processed @theuni 's comments. WIll merge as soon as Travis passes. |
|
Thanks. ut ACK. |
Pardon a bit of iteration. This continues/fixes #6719. `event_base_loopbreak` was not doing what I expected it to. What I expected was that it sets a timeout, given that no other pending events it would exit in N seconds. However, what it does was delay the event loop exit with 10 seconds, even if nothing is pending. Solve it in a different way: give the event loop thread time to exit out of itself, and if it doesn't, send loopbreak. This speeds up the RPC tests a lot, each exit incurred a 10 second overhead, with this change there should be no shutdown overhead in the common case and up to two seconds if the event loop is blocking. As a bonus this breaks dependency on boost::thread_group, as the HTTP server minds its own offspring.
This continues/fixes #6719. `event_base_loopbreak` was not doing what I expected it to, at least in libevent 2.0.21. What I expected was that it sets a timeout, given that no other pending events it would exit in N seconds. However, what it does was delay the event loop exit with 10 seconds, even if nothing is pending. Solve it in a different way: give the event loop thread time to exit out of itself, and if it doesn't, send loopbreak. This speeds up the RPC tests a lot, each exit incurred a 10 second overhead, with this change there should be no shutdown overhead in the common case and up to two seconds if the event loop is blocking. As a bonus this breaks dependency on boost::thread_group, as the HTTP server minds its own offspring.
Fix various thread assertion errors caused during shutdown. Cherry-picked from the following upstream PRs: - bitcoin/bitcoin#6719 - bitcoin/bitcoin#6990 - bitcoin/bitcoin#8421 - Second commit only in this PR - bitcoin/bitcoin#11006 I've cherry-picked the relevant commits, along with a note in each commit referring to the original Bitcoin commit ID (and the Zcash issue numbers where applicable). I've tested each issue with/without these patches applied. Closes #2214, #2334, and #2554.
HTTP Server cherries from Core: bitcoin/bitcoin#6719 - Make HTTP server shutdown more graceful bitcoin/bitcoin#6859 - http: Restrict maximum size of http + headers bitcoin/bitcoin#6990 - http: speed up shutdown bitcoin/bitcoin#7966 - http: Do a pending c++11 simplification handling work items bitcoin/bitcoin#8421 - httpserver: drop boost (#8023 dependency) bitcoin/bitcoin#11006 - Improve shutdown process
HTTP Server cherries from Core: bitcoin/bitcoin#6719 - Make HTTP server shutdown more graceful bitcoin/bitcoin#6859 - http: Restrict maximum size of http + headers bitcoin/bitcoin#6990 - http: speed up shutdown bitcoin/bitcoin#7966 - http: Do a pending c++11 simplification handling work items bitcoin/bitcoin#8421 - httpserver: drop boost (#8023 dependency) bitcoin/bitcoin#11006 - Improve shutdown process
Shutting down the HTTP server currently breaks off all current requests. This can create a race condition with RPC
stopcommand, where the calling process never receives confirmation.This change removes the listening sockets on shutdown so that no new requests can come in, but no longer breaks off requests in progress.
Meant to fix #6717.