Code review request for extending svcs to "ordinary" python apps #102
Replies: 1 comment
-
Hmmm, that's too much code for me to have a "quick look", but I've recently ran into atexit issues too and came to the conclusion, that atexit should only be used by the entrypoint of the application and all other hooks should be handled separately. So for example in WSGI apps, the concept of an application creation pattern is quite common. But, it doesn't handle cleanup at all and calling atexit within the app factory comes with many problems, some of which you've described, but also that it's icky in tests when you potentially run it many times. So what I've started doing is that my application factories return a tuple of Concrete example: from __future__ import annotations
import atexit
from ...config import WebAppConfig
from .app_maker import make_wsgi_app
app_cfg = WebAppConfig.from_environ() # type: ignore[attr-defined]
application, cleanup = make_wsgi_app(app_cfg)
atexit.register(cleanup) So that's for lifecycle at application scope – while this one is WSGI-specific, I think the concept of central entry points that are guaranteed to be only called once and application factories that centralize resource management is a good idea for any type of application. As for your per-thread lifecycle issues – you said it's your application, so shouldn't you be able to add a lifecycle management yourself? At least that's what I did for example for our task queue. It's impossible to give you generic advice based on what I've seen, but the question is "who's creating the threads/asyncio tasks that should own a fresh container?" Generally speaking: contextmanagers are GREAT for this. |
Beta Was this translation helpful? Give feedback.
-
I wanted to use svcs in some of my side projects (almost entirely single or multi threaded CLI tools) before I use this library in work apps
I came up with a few options for where to put the global state (ContextVars seems to the new asyncio safe global-like thing)
https://github.com/matthewdeanmartin/svcs/blob/main/src/svcs/thread_alt.py#L24
Python just lacks life cycle events like frameworks or other languages (C# has a variety of app lifecycle events even for a CLI tool)
So I made some decorator/context managers. Not clever, but I couldn't think of anything better.
https://github.com/matthewdeanmartin/svcs/blob/main/src/svcs/thread_alt.py#L440
Using the one life cycle we got, it has problems.
atexit has problems (can't handle multiple registrations for multiprocess/multithread apps), you get 1 per start of app. There is a multi atexit hack out there.
Anyhow, my hack basically works on my machine, but weighing the advantages of monkeypatching current_thread, theading_local or ContextVars (the latter seems to still require using a global somehow) is getting over my head.
Beta Was this translation helpful? Give feedback.
All reactions