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
Refactor Qtile LifeCycle #2046
Refactor Qtile LifeCycle #2046
Conversation
CI failure seems to be unrelated :/ |
yeah, let's run them again |
ugh mypy, I'll need to get that working locally tomorrow |
9c043d5
to
87fd8da
Compare
Added the appropriate mypy hints |
Why not just |
maybe_restart is a bound method. I wanted to give all objects, especially qtile and the things it owns, a chance to be finalized before os.execv. Edit: sorry, had a toddler climbing on me. The other big reason is that we want the atexit handler to be the last thing executed by the python vm since os.execv is going to instantly terminate without cleaning up. That means it needs to be the first thing registered. Beyond the need I felt that having process lifecycle management outside of qtile was a better design for testing, embedding in other programs, etc. Also, the reason lifecycle is not a class is to reduce the number of objects that would still be alive atexit |
Okay, that's what I thought. :) You made a perfect transition to what I was going to say next with your last sentence, eh: I'd prefer everything in lifecyle.py to be in a class so that we could avoid the setters and getters that are just proxies over global objects. I think that we don't care having such a class instance still alive at exit. I was thinking of something along these lines: class Lifecyle:
def __init__(self):
self.behavior = Behavior.TERMINATE
...
def teardown(self):
if self.behavior = Behavior.RESTART:
...
lifecycle = Lifecycle()
atexit.register(lifecycle.teardown) Then we could probably manage other things from Qtile's lifecycle... but I feel that's a bit redundant with SessionManager, so maybe we should just merge both features here? PS: I do have toddlers yelling around as well, so I feel you! |
Fair enough! I'll make that change in a bit. |
87fd8da
to
65b9689
Compare
Done! |
Cool, but did you see the last part of my previous comment? 👀
|
I agree with the merge with SessionManager. It is managing the session after all! This may involve some playing around with conftest.py. |
I'll see about merging lifecycle + session manager either tonight or tomorrow. I'll also go ahead and get rid of that setter... my reasons for keeping it were just to make the method signature match execv so it was kind of like a delayed call but that's probably not that valuable anyways. |
65b9689
to
301db38
Compare
Done! |
segfault :/ |
Is it feasible to have the new session manager logic contained within the session manager itself, rather than having this bi-directional relationship between it and the qtile object? |
qtile needs some way to signal the session manager that it would like to restart instead of terminate, what did you have in mind? |
Relevant IRC logs:
|
planning on breaking out loop setup/teardown and atexit stuff into different files |
segfault but tests pass! invasive work done, now to make it prettier |
81646ef
to
9e01e86
Compare
I should also mention that this slightly changes how different config hooks are fired. For instance, in my config I was using asyncio.run as a crude method of having async handlers for hooks like startup and startup_once. With this change that no longer works, it errors informing the user that they cannot use asyncio.run inside of an existing event loop. Since my use case did not require awaiting a result, I simply changed asyncio.run to asyncio.create_task |
Confirmed dbus is working normally after these changes. Was able to use both the notification widget as well as elparaguayo's upower/dbus based battery widgets successfully with no errors. I was able to send notifications and see them displayed in my bar with both |
592a254
to
749c77f
Compare
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.
Thank you so much for your work, it looks like it really improves the overall code workflow! That being said, and maybe because I find this PR really important, the diff is still a bit too complicated to get my approval for two reasons:
-
I feel that the interaction between the three classes LifeCycle, QtileLoop and SessionManager complicates the overall architecture for a small benefit, since both the LifeCycle and QtileLoop classes are only used in SessionManager. What kind of advantage do you see in the current implementation? Could we merge LifeCycle into QtileLoop and include it in session_manager.py, for example?
-
Your small unnecessary modifications here and there really make it tedious to read the commits and will clutter the history if we merge them. I know it takes time on your side to change and I'm sorry I have to ask you to work on this since it makes me feel like I'm nitpicking, but with a codebase of this size it's really important that everyone does atomic commits or digging through history becomes a nightmare when we need to.
I really want us to get this done and I'm sure it's going to be a big improvement for Qtile overall, so feel free to come bug me on IRC if you want a faster feedback than here. :)
749c77f
to
4aec381
Compare
1a9c41e
to
8e33c2b
Compare
Also cleans up qtile.__init__ a bit
0e7d47d
to
ed0edcd
Compare
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.
LGTM 🚀
Refactors the process lifecycle related parts of Qtile to properly manage resource finalization and just generally cleans up the code. Instead of running os.execv before python's builtin finalization routines, this uses those same finalization routines to move os.execv to the last thing done by the interpreter before termination.
ed0edcd
to
6648b37
Compare
After thinking about this some more, I'm still not convinced that this is the right way to solve the problem. It seems the argument in favor of it was "we run the python garbage collector this way, which fixes things". However, we shouldn't need to run the garbage collector: reclaiming memory isn't necessary before exec(). So, this suggests that whatever bug this patch was fixing is a poor use of
Shouldn't we be closing this manually on shutdown via the code in the finally block of |
os.execv would skip |
Yes, but read the code -- the finally block happens before the exec(). |
Now I have no idea what you're talking about. Can you provide some context? snippets? |
Sorry, I'd hoped,
was enough: qtile/libqtile/core/session_manager.py Line 50 in f3add88
|
This PR refactors the process lifecycle related parts of Qtile to properly manage resource finalization and just generally cleans up the code.
Instead of running os.execv before python's builtin finalization
routines, this uses those same finalization routines to move os.execv to
the last thing done by the interpreter before termination.