-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
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
Checking for sys.is_finalizing
before thread.start() still yields "can't create new thread at interpreter shutdown"
#114570
Comments
There are few stages of shutdown. New threads cannot be started and the process cannot be forked at interpreter shutdown. But there is also global runtime shutdown, and Perhaps |
Previsously, I proposed adding a new Would adding a new more specific The problem with checking for It was related to #109047 but I decided to fix the multiprocessing bug without |
Yes, it should be used to check the cause of error after it happens. But it can also be used in optimistic check to prevent costly operations at shutdown. For example: if not is_finalising():
try:
do_something_expensive()
except CantDoError:
if is_finalising():
# okay
else:
# kaboom! The problem in this issue is that |
This would solve my issue pretty well. I will also add that being able to preemptively check like @serhiy-storchaka provided in the example would also be a great option. |
The problem is that checking sys.is_finalizing after catching the thread.start RuntimeError does not work either; sys.is_finalizing returns False even though thread.start says the interpreter is shutting down. |
I'd be in favor of making it report the current interpreter's status. That could make use of We could add something like |
tl;dr We should at least make
The problem is that (expand for extra info)This is partly because we are a bit inconsistent about how we report "finalizing":
When the runtime (ergo main interpreter) is finalizing, we do the following:
(The same thing happens for all other subinterpreters except step 6.) So, back to the reported problem, there are two different definitions of "finalizing" at play.
Possible solutions:
Note that each of those solutions would only help with 3.13+, and not with 3.12 and earlier. In the meantime, I suppose you could get fancy with ctypes in the meantime (though I wouldn't recommend it), or you could access the right information with a custom extension module. Footnotes
|
It would be less controversial to add I'd like to see More generally, I'd really like to have something like Also see: gh-110490 |
Add PythonFinalizationError exception. This exception derived from RuntimeError is raised when an operation is blocked during the Python finalization. The following functions now raise PythonFinalizationError, instead of RuntimeError: * _thread.start_new_thread() * subprocess.Popen at fork * os.fork() * os.fork1() * os.forkpty() Morever, _winapi.Overlapped finalizer now logs an unraisable PythonFinalizationError, instead of an unraisable RuntimeError.
Add PythonFinalizationError exception. This exception derived from RuntimeError is raised when an operation is blocked during the Python finalization. The following functions now raise PythonFinalizationError, instead of RuntimeError: * _thread.start_new_thread() * subprocess.Popen * os.fork() * os.fork1() * os.forkpty() Morever, _winapi.Overlapped finalizer now logs an unraisable PythonFinalizationError, instead of an unraisable RuntimeError.
As a first step forward, I wrote a new PR gh-115352 to add |
Add PythonFinalizationError exception. This exception derived from RuntimeError is raised when an operation is blocked during the Python finalization. The following functions now raise PythonFinalizationError, instead of RuntimeError: * _thread.start_new_thread() * subprocess.Popen * os.fork() * os.fork1() * os.forkpty() Morever, _winapi.Overlapped finalizer now logs an unraisable PythonFinalizationError, instead of an unraisable RuntimeError.
Add PythonFinalizationError exception. This exception derived from RuntimeError is raised when an operation is blocked during the Python finalization. The following functions now raise PythonFinalizationError, instead of RuntimeError: * _thread.start_new_thread() * subprocess.Popen * os.fork() * os.fork1() * os.forkpty() Morever, _winapi.Overlapped finalizer now logs an unraisable PythonFinalizationError, instead of an unraisable RuntimeError.
Bug report
Bug description:
We have code in pymongo Our
MongoClient
object immediately spawns a new daemon thread to run some periodic check operations from the moment it is initialized. When run on python 3.12, we've run into the issuecan't create new thread at interpreter shutdown
because we have casesthread.start()
that can execute as the interpreter is shutting down.To mitigate this issue we attempted checking
sys.is_finalizing
before issuing thestart()
call:This still generated the same runtime error.
We tried catching the
RuntimeError
exception:This worked. This feels too broad a solution than the above since it will catch and ignore all
RuntimeError
s.Finally we decided to see if we could check
sys.is_finalizing
after the exception is raised.To our surprise, this also failed. I can understand that starting a thread on interpreter shutdown should be avoided, but this also feels misleading if the system isn't correctly seeing--which is my assumption on what
sys.is_finalizing()
--that it is experiencing interpreter shutdown.Should the expectation not be that
sys.is_finalizing
is updated before thethread.start()
is called OR by the time theRuntimeError
is raised? This way we can safely catch or preempt the error before triggering?As a general inquiry, though, what should be the general best practice for patching issues like this on our end as it has introduced somewhat breaking behavior from 3.11 -> 3.12? Should we do like above with catching the
RuntimeError
but additionally check the exception string for the exact type ofRuntimeError
?CPython versions tested on:
3.12
Operating systems tested on:
macOS
Linked PRs
The text was updated successfully, but these errors were encountered: