Context manager, atexit processing, and PEP 3143 DaemonContext.close
Ben Finney
ben+python at benfinney.id.au
Sat May 16 20:50:23 EDT 2009
Howdy all,
I'm slowly developing PEP 3143 and, in parallel, its reference
implementation, the ‘python-daemon’ library
<URL:http://pypi.python.org/pypi/python-daemon/>. Feedback continues to
be welcome from people wanting to make a program become a daemon; please
try it out and critique the specification and/or the implementation.
Today a flaw has been uncovered by Pavol Babinčák. In diagnosing an
issue, we doscovered that PEP 3143 currently leads, in some common
circumstances, to exiting a context manager twice.
The current specification of the `DaemonContext` class says:
=====
close()
Return: None
Close the daemon context. This performs the following step:
* If the pidfile attribute is not None, exit its context
manager.
=====
and:
=====
__exit__(exc_type, exc_value, exc_traceback)
Return: True or False as defined by the context manager
protocol
Call the instance's close() method, then return True if the
exception was handled or False if it was not.
=====
but also:
=====
open()
Return: None
Open the daemon context, turning the current program into a daemon
process. This performs the following steps:
[…]
* Register the close method to be called during Python's exit
processing.
=====
This leads to the situation where the `DaemonContext.close` method can
be called twice:
pidfile = FunkyLockFile()
daemon_context = daemon.DaemonContext(pidfile=pidfile)
with daemon_context:
main_processing()
According to the current specification, this will cause
`daemon_context.close()` to be called on exiting its context manager (at
the end of the `with` suite) *and* on program exit (via `atexit`
processing).
This will cause the `pidfile` context manager to be exited twice in
succession, which surely can't be good and is at least undefined AFAICT.
How should a context manager be implemented to handle situations like
this? One possible way is to raise an exception when trying to close a
not-open context manager. Another is to return immediately if the
attempt is made, making it safe to try closing a context manager
multiple times.
The “Register the close method to be called during Python's exit
processing” is there to ensure clean-up occurs even if the program
isn't using the DaemonContext as a context manager. Ideally, what I'd
like to do is *un*-register the `close` method after having already
closed it, so that exit processing *won't* call it. The `atexit` module,
though, doesn't appear to give me that option.
Ideas? How should this be addressed both Pythonically and respecting the
intent of PEP 3143?
--
\ “For fast acting relief, try slowing down.” —Jane Wagner, via |
`\ Lily Tomlin |
_o__) |
Ben Finney
More information about the Python-list
mailing list