Closed Avriox closed 2 years ago
NiceGUI is using uvicorn as a server which has still problems with graceful shutdowns (see https://github.com/encode/uvicorn/discussions/1103 for example). We need to think about this a bit. My not so graceful suggestion would be to start NiceGUI without reload=True
, launch a new process on exit and just live with exceptions printed on the console:
from nicegui import ui
import sys
def apply():
print('Starting main system in seperate process')
# subprocess.Popen(['python3', 'my_main_system.py'])
sys.exit(0)
ui.label('Configuration')
ui.label('... your config UI here ...')
ui.button('Apply', on_click=apply)
ui.run(reload=False)
Yes, it would be great to have something like
from nicegui import ui
ui.label('Your configurtion UI...')
def quit():
... # How?
ui.button('Quit', on_click=quit)
ui.run(reload=False)
print('Do something else...')
It's a pity that uvicorn.run()
starts a server
that's not exposed to the outside, but would have a server.shutdown()
method.
Monkey-patching uvicorn.run()
(or simply copying its content over into our run.py
) would be an option. But due to the many configuration options thats more than 120 lines of code and doesn't feel quite right.
The solution multiprocessing.Process
-Solution described in https://stackoverflow.com/a/70980373/364388 looked promising. But the whole app needs to be pickled... which does not work in NiceGUI:
AttributeError: Can't pickle local object 'CustomView.use.<locals>.<lambda>'
I've pushed the code to branch #83-Process.
I've got a first idea working on #83-ui.shutdown.
The main idea stems from @falkoschindler https://github.com/zauberzeug/nicegui/issues/83#issuecomment-1241787394. We could simply create the uvicorn server object inside nicegui instead of relying on the uvicorn.run
helper. The API may look as following:
ui.button('Quit', on_click=ui.shutdown)
But there is still work to be done. For example auto-reloading is still broken.
I tried to add more code from uvicorn.run
: https://github.com/zauberzeug/nicegui/commit/501323de11808385571b0c2d90d3a06bd1d8c04d
Now the app starts with reload=False
and reload=True
. But with auto-reload the "Quit" button does not work, because the spawned process has no nicegui.globals.server
set. That's only the case in the parent process. But maybe we don't need reloading anyway. We could simply raise an exception that ui.shutdown
does not work with reload=True
.
Another issue: When the socket connection is lost due to the server being shut down, the JustPy frontend asks for confirmation to reload the page. This makes no sense and should be avoided.
Nice! After moving ui.shutdown into the lifecycle module the reload-confirmation dialog is gone.
ui.shutdown
Correction: app.shutdown
Is there any way of gracefully shutting down the server after use? I am using it to have a configuration page for a larger project and once the configuration is completed the main part of the project takes over and no more configuration is needed. I would like to kill everything UI related at that point.