Skip to content
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

fix(python-plugin): update internal interpreter state immediately upon forking #2388

Merged
merged 2 commits into from
Mar 21, 2022

Conversation

majorgreys
Copy link
Contributor

@majorgreys majorgreys commented Dec 26, 2021

Fixes #2387

This PR adds pre_uwsgi_fork and post_uwsgi_fork hooks to uwsgi_plugin in order to update the internal interpreter state of CPython immediately before and immediately after the call to uwsgi_fork. This follows the implementation of the standard library os.fork() in CPython.

While these two hooks effectively replace existing code to update the internal interpreter state during the lifecycle of master and worker processes, we preserve the current behavior for uWSGI LTS. We instead provide a new option py-call-uwsgi-fork-hooks to enable the new feature.

We add test coverage for the issue of deadlocked workers raised in #2387 parameterized for relevant configurations options.

uwsgi.h Outdated
@@ -1039,6 +1039,8 @@ struct uwsgi_plugin {
void *data;
void (*on_load) (void);
int (*init) (void);
void (*pre_uwsgi_fork) (void);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move it at the end of the structure for maintaining ABI?

core/uwsgi.c Outdated
@@ -3338,14 +3338,6 @@ int uwsgi_start(void *v_argv) {
}
}

// master fixup
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should leave this part in for not breaking other plugins

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@unbit I did not see the master_fixup hook used elsewhere in the repository but that doesn't mean it's not used by a plugin a user might have, so I can add this back. Are you aware of such a plugin?

core/mule.c Outdated
@@ -69,12 +69,6 @@ void uwsgi_mule(int id) {

uwsgi_close_all_sockets();

for (i = 0; i < 256; i++) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should leave this part in for not breaking other plugins

@unbit
Copy link
Owner

unbit commented Dec 27, 2021

@majorgreys thanks a lot, my only doubt (in addition to the review comments) is about the old (and ugly, obviously) up.call_osafterfork. Basically it loses any meaning with your patch so i think we can safely remove this (at least in master). For LTS i would probably introduce this new behaviour (albeit definitely correct) as an option. I know it is annoying but LTS grants the user that we do not break/change old stuff (honestly i am not sure about the implications, very probably only app-managed signal management will be affected, and in a positive way). @xrmx any thought?

@majorgreys majorgreys changed the title fix(cpython): update internal interpreter state immediately upon forking fix(python-plugin): update internal interpreter state immediately upon forking Dec 27, 2021
@majorgreys
Copy link
Contributor Author

majorgreys commented Dec 27, 2021

I've updated the change now to make it so the old behavior can be retained, specifically with regards to call_osafterfork.

Given the needs of LTS, I'm inclined to focus this PR on non-breaking changes so it can be easily backported to the 2.0 branch and open a separate PR for the breaking changes so that they can end up on master. @unbit Does that work for what you had in mind for how to introduce these changes?

@majorgreys majorgreys requested a review from unbit December 29, 2021 05:35
@majorgreys
Copy link
Contributor Author

@unbit @xrmx I have updated the PR to introduce this as an opt-in feature and avoid any breaking changes so it can be backported into the LTS 2.0 branch.

@brettlangdon
Copy link

@unbit or @xrmx have you had a chance to look over this PR again? Is there anything else you would like us to update?

@majorgreys
Copy link
Contributor Author

👋🏽 @unbit Any update on this PR? I addressed the concerns you raised with regards to merging this into LTS.

@xrmx xrmx merged commit b7a5cf1 into unbit:master Mar 21, 2022
@xrmx
Copy link
Collaborator

xrmx commented Mar 21, 2022

Merged and broke master CI :)
Search for "ERROR: uWSGI did not start"
https://github.com/unbit/uwsgi/runs/5633992704?check_suite_focus=true

@majorgreys
Copy link
Contributor Author

@xrmx Thanks for the heads up. I'll see if I can reproduce this locally.

@Superskyyy
Copy link

Superskyyy commented Nov 23, 2022

@majorgreys Hello, thanks for fixing the issue, but I was trying the new option py-call-uwsgi-fork-hooks and the following ignored exception prints out if and only if the enable-threads option is given.

uwsgi --http :9090 --wsgi-file demo/uwsgi_app.py --py-call-uwsgi-fork-hooks --processes 4 works fine,
uwsgi --http :9090 --wsgi-file demo/uwsgi_app.py --enable-threads --py-call-uwsgi-fork-hooks --processes 4 prints the following errors.
`


Exception ignored in: <function _after_at_fork_child_reinit_locks at 0x7fd01e7ecdc0>
Traceback (most recent call last):
  File "/home/gitpod/.pyenv/versions/3.8.13/lib/python3.8/logging/__init__.py", line 264, in _after_at_fork_child_reinit_locks
    _releaseLock()  # Acquired by os.register_at_fork(before=.
  File "/home/gitpod/.pyenv/versions/3.8.13/lib/python3.8/logging/__init__.py", line 232, in _releaseLock
    _lock.release()
RuntimeError: cannot release un-acquired lock

This was discussed here but remains unresolved, can you help to see if it is my env problem or something else? Really appreciated.

@majorgreys
Copy link
Contributor Author

@Superskyyy I need to still review the linked issue but I can confirm that I can reproduce this error. I don't see it when --py-call-uwsgi-fork-hooks is not used along with --enable-threads.

#2179 also reported the same exception when --py-call-osafterfork was used.

Code for minimal reproduction: https://gist.github.com/majorgreys/3ee1716b107ad80226b12145ae87276a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

cpython: deadlocked workers if thread started before forking
5 participants