Closed josephernest closed 4 years ago
The controlling part here is not bottle, but the server implementation. bottle.run()
simply starts the selected wsgi-server and tells it to loop forever. Some have a shutdown method, but it is hard to get hold of it when using the run()
convenience method and not start the server yourself. Most gracefully shutdown if they receive a SIGINT
signal or encounter a SystemExit
or KeyboardInterrupt
exception. So, sys.exit()
should do the trick.
That said, it is unusual to stop a server from within. You usually send a SIGINT
from outside.
As for cleanup code: SIGINT
triggers a KeyboardInterrupt
in all running threads (if I remember correctly). So, finally blocks are still executed. But there is no guarantee. Never rely on clean-up code to run before a process terminates. SIGTERM
, SIGHUB
and SIGKILL
will all ignore finally blocks and immediately exit the interpreter.
Thank you for your answer. Last questions:
When using WSGIRefServer()
, is there a way to call its stop
method, and if so, how?
How to call your function close()
https://github.com/bottlepy/bottle/blob/master/bottle.py#L864 from inside a route?
I tried sys.exit(0)
from inside a route, but the Bottle app continues running
Here is the context (maybe you have an idea): https://stackoverflow.com/questions/61600356/how-to-commit-db-changes-in-a-flask-or-bottle-app-efficiently
I can't do SQLite db.commit()
after each request (100ms is too much when there are many clients) so I wanted to do once every 30 seconds, but I need to be sure that it happens if the server is stopped. So I need to be able to have a stop
handler.
SIGINT
in some situations, which is plain wrong. I do not know if they fixed that in recent releases. cheroot has proper start()
and stop()
methods. Perhaps try that.Bottle.close()
does not stop the server. Bottle itself is not a server, it is run by a server. Bottle cannot stop it natively.If you are concerned about 100ms for a blocking db.commit()
perrequst then perhaps stop using a single-threaded WSGI server implementation (wsgiref)? You are optimising at the wrong end.
Thanks for your answer, I'll study this.
PS: It seems this has been added recently to Bottle: https://github.com/josephernest/bottle/blob/master/bottle.py#L3282
self.srv = make_server(self.host, self.port, app, server_cls,
handler_cls)
instead of
srv = make_server...
This is interesting because then we can simply do
server = bottle.WSGIRefServer(port=80)
bottle.run(server=server)
and this in a route:
server.srv.shutdown()
Is that correct?
Not a public or documented API, but that might work, yes. I'd still move away from wsgref as soon as possible.
Thanks for the advice @defnull. Last thing: what do you think of this solution found on stackoverflow:
I eventually found the solution was to do:
sys.stderr.close()
inside the request (that got passed up to the bottle server and axed it).
? I tried and it works indeed.
The solution I found is:
bottle is started with
run(app, reloader=False, host='0.0.0.0', debug=True, quiet=True, port=2020)
And shutdown of the server including release of the ports is done via:
import psutil import signal
@app.route('/shutdown') def shutdown():
https://stackoverflow.com/a/60888399
current_process = psutil.Process() current_process.send_signal(signal.SIGTERM)`
I would like to be able to
stop
the server from a route, something like that:but
app.stop()
is not defined.How to stop a server from code?
Is there a
stop
function?Or should we send a SIGKILL / SIGTERM ? Then is there a listener to do some final cleanup before the server stops?