[Twisted-Python] Problem: spawnProcess() never ending when installSignalHandlers=False
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
Hello. I'm using Twisted 1.3.0 on python2.4 on an Ubuntu-Hoary x86 Linux box. I'm using twisted and spawnProcess() with a Queue structure to chain processes that need to be called (specifically, imagemagick commands). I use the "processEnded" event/method of t.i.p.ProcessProtocol to go from one task to the next. Twisted shares a python process with a multi-threaded web-app-kit (Webware) so it has to be run in a thread. This worked well on other older versions of twisted and older versions of python; also on linux. I've tracked down the problem to be twisted itself (or my incorrect use of it) rather than my code. This example illustrates it: ------------------------------------------------- from twisted.internet import reactor from twisted.internet.protocol import ProcessProtocol class MyProt( ProcessProtocol ): def processEnded(self, reason): print "ended.", reason executable = '/bin/touch' args = ( '/tmp/foo.txt', ) args = (executable,) + tuple(args) reactor.spawnProcess( MyProt(), executable, args ) reactor.callLater( 5, reactor.stop ) #reactor.run() reactor.run(installSignalHandlers=False) ------------------------------------------------- As is, this code never runs the "processEnded()" method of MyProt(). If I change the reactor.run() parameter to leave the signal handlers on, it works. Note that I need to leave the signal handlers turned off because I can't run the reactor in the main thread; Webware needs that. I also know that the subprocess is giving up its file descriptors; I can see that if I put more print statements into MyProt(). And I know that the subprocess is working; /tmp/foo.txt is there. It seems that somehow the reactor is using signals to notice when a process has ended; this makes a certain ammount of sense intuitively, though I don't understand the nitty-gritty of processes and signals at all. And more importantly, this has worked before on other combinations of twisted/python. Is this a bug? If so, has it been fixed? If not, what should I do to detect when a spawned process is finished? Thanks very much. Twisted rocks.
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
On 6/10/05, Itamar Shtull-Trauring <itamar@itamarst.org> wrote:
Thanks. So this behavior is by design? Again, it DID work before; for the last year or so, I've been using this code in production on a few servers. Perhaps a note could be made in the docs that ProcessProtocol doesn't work in this case. This will make it pretty hard to integrate into other worlds. I'm not sure that I can over-ride the signal handling in Webware and register handlers. Other bits of python libraries might be the same way. I look forward to any "more general solution" that anyone can come up with! Would the "twisted way" would be to run the reactor in a different python process and talk to it via rpc? The problem, of course, is that the best way to do that on the client end of the rpc is twisted, too! Thanks again.
![](https://secure.gravatar.com/avatar/7ed9784cbb1ba1ef75454034b3a8e6a1.jpg?s=120&d=mm&r=g)
On Sat, 11 Jun 2005 11:08:12 -0400, Matt Feifarek <matt.feifarek@gmail.com> wrote:
Yep, and always has been. If it ever worked, it was by accident (I really don't see how it could have, though, so I can't begin to guess what might have changed to stop it).
Here's one: def reapChildren(): from twisted.internet import reactor, task t = task.LoopingCall(reactor._handleSigchld, None, None) return t.start(5) Of course, it uses a non-public method of reactor (but installSignalHandlers is a non-public argument to reactor.run(), so you're already treading on thin ice :) Jp
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
On 6/11/05, Jp Calderone <exarkun@divmod.com> wrote:
Of course, it uses a non-public method of reactor (but installSignalHandlers is a non-public argument to reactor.run(), so you're already treading on thin ice :)
Thanks. I don't see how it's non-public. Twisted TELLS you to use it if you run the reactor in a thread. That doesn't seem too secret to me. But thanks for the suggestion.
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
You're right; I stand corrected. What it DOES say is this: ValueError: signal only works in main thread Somebody here in the list or maybe on #twisted told me about the installSignalhandlers, I guess I must have conflated the two directives. It's been so long that I don't remember. As I said, I'm using this on 3 servers right now to serve thousands of image requests and convert them on the fly if necessary. Oh well. Time to find a new way. Thanks very much for your help. On 6/11/05, Jp Calderone <exarkun@divmod.com> wrote:
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 13, 2005, at 11:40 PM, Matt Feifarek wrote:
Oh well. Time to find a new way.
I'd suggest continuing to do it the way you are currently. While installSignalHandlers may be undocumented, it's not just going to disappear overnight. If you use that parameter and task.LoopingCall(process.reapAllProcesses).start(1.0, now=False) then I'd say you're on fairly safe ground for the immediate future. Overall we do a good job of keeping backwards compatibility even for APIs that may not be completely official, so it's unlikely to just up and disappear. James
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
James Y Knight wrote:
On Jun 13, 2005, at 11:40 PM, Matt Feifarek wrote:
Perhaps a better way to handle this would be to create an official API to handle this problem, then distribute it as an external Python file you can include, which will have some forward-compatibility code put into it when newer versions of Twisted come out. I don't like the "let's never change anything because someone might be using it somewhere" approach that we've been taking. When we're making minor changes it's good but over time (especially given the sprawling nature of Twisted and the lack of any documentation on the state of its entirety) means tha we leave chunks of deprecated or semi-deprecated APIs around forever.
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 14, 2005, at 10:45 AM, Glyph Lefkowitz wrote:
That points to a need to better track deprecated APIs and when they are planned to be removed, not to a need to break things more. Stability is good, and without an easy way to verify conformance, it is dangerous to say that stability in undocumented interfaces is unimportant. It believe that an undocumented interface should be considered less important to keep stable, but it should still be done if possible. This is especially true in the twisted core, vs the various protocol packages, most of which are significantly less well developed and in some cases just have stupidly broken APIs. For this particular case, I can't think of any reason why an installSignalHandlers=0 argument would ever need to be removed. James
![](https://secure.gravatar.com/avatar/3c4988f83703127d279406fc6eea7079.jpg?s=120&d=mm&r=g)
From an old thread[1]:
On Sat, 2005-06-11 at 11:35 -0400, Jp Calderone wrote:
I'm trying to diagnose an intermittent pausing problem on Win32, and t.i.process is unavailable on that platform, which reapChildren() relies on. Is there no need for this approach when launching the reactor with installSignalHandlers=0 on Windows? Steve [1]http://twistedmatrix.com/pipermail/twisted-python/2005-June/010692.html
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 11, 2005, at 11:08 AM, Matt Feifarek wrote:
There is one. It logs "spawnProcess called, but the SIGCHLD handler is not installed. This probably means you have not yet called reactor.run, or called reactor.run(installSignalHandler=0). You will probably never see this process finish, and it may become a zombie process." However, your example doesn't have logging setup, so you don't see that message.
If you cannot override the signal handling, do something like: from twisted.internet import task task.LoopingCall(process.reapAllProcesses).start(1.0, now=False) That's less efficient but will work. I have a vague recollection that in old versions twisted used to do this by default but I might just be making that up. James
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
On 6/10/05, Itamar Shtull-Trauring <itamar@itamarst.org> wrote:
Thanks. So this behavior is by design? Again, it DID work before; for the last year or so, I've been using this code in production on a few servers. Perhaps a note could be made in the docs that ProcessProtocol doesn't work in this case. This will make it pretty hard to integrate into other worlds. I'm not sure that I can over-ride the signal handling in Webware and register handlers. Other bits of python libraries might be the same way. I look forward to any "more general solution" that anyone can come up with! Would the "twisted way" would be to run the reactor in a different python process and talk to it via rpc? The problem, of course, is that the best way to do that on the client end of the rpc is twisted, too! Thanks again.
![](https://secure.gravatar.com/avatar/7ed9784cbb1ba1ef75454034b3a8e6a1.jpg?s=120&d=mm&r=g)
On Sat, 11 Jun 2005 11:08:12 -0400, Matt Feifarek <matt.feifarek@gmail.com> wrote:
Yep, and always has been. If it ever worked, it was by accident (I really don't see how it could have, though, so I can't begin to guess what might have changed to stop it).
Here's one: def reapChildren(): from twisted.internet import reactor, task t = task.LoopingCall(reactor._handleSigchld, None, None) return t.start(5) Of course, it uses a non-public method of reactor (but installSignalHandlers is a non-public argument to reactor.run(), so you're already treading on thin ice :) Jp
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
On 6/11/05, Jp Calderone <exarkun@divmod.com> wrote:
Of course, it uses a non-public method of reactor (but installSignalHandlers is a non-public argument to reactor.run(), so you're already treading on thin ice :)
Thanks. I don't see how it's non-public. Twisted TELLS you to use it if you run the reactor in a thread. That doesn't seem too secret to me. But thanks for the suggestion.
![](https://secure.gravatar.com/avatar/9a7b191de8b6ec7fe0d6c66d0a5512fa.jpg?s=120&d=mm&r=g)
You're right; I stand corrected. What it DOES say is this: ValueError: signal only works in main thread Somebody here in the list or maybe on #twisted told me about the installSignalhandlers, I guess I must have conflated the two directives. It's been so long that I don't remember. As I said, I'm using this on 3 servers right now to serve thousands of image requests and convert them on the fly if necessary. Oh well. Time to find a new way. Thanks very much for your help. On 6/11/05, Jp Calderone <exarkun@divmod.com> wrote:
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 13, 2005, at 11:40 PM, Matt Feifarek wrote:
Oh well. Time to find a new way.
I'd suggest continuing to do it the way you are currently. While installSignalHandlers may be undocumented, it's not just going to disappear overnight. If you use that parameter and task.LoopingCall(process.reapAllProcesses).start(1.0, now=False) then I'd say you're on fairly safe ground for the immediate future. Overall we do a good job of keeping backwards compatibility even for APIs that may not be completely official, so it's unlikely to just up and disappear. James
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
James Y Knight wrote:
On Jun 13, 2005, at 11:40 PM, Matt Feifarek wrote:
Perhaps a better way to handle this would be to create an official API to handle this problem, then distribute it as an external Python file you can include, which will have some forward-compatibility code put into it when newer versions of Twisted come out. I don't like the "let's never change anything because someone might be using it somewhere" approach that we've been taking. When we're making minor changes it's good but over time (especially given the sprawling nature of Twisted and the lack of any documentation on the state of its entirety) means tha we leave chunks of deprecated or semi-deprecated APIs around forever.
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 14, 2005, at 10:45 AM, Glyph Lefkowitz wrote:
That points to a need to better track deprecated APIs and when they are planned to be removed, not to a need to break things more. Stability is good, and without an easy way to verify conformance, it is dangerous to say that stability in undocumented interfaces is unimportant. It believe that an undocumented interface should be considered less important to keep stable, but it should still be done if possible. This is especially true in the twisted core, vs the various protocol packages, most of which are significantly less well developed and in some cases just have stupidly broken APIs. For this particular case, I can't think of any reason why an installSignalHandlers=0 argument would ever need to be removed. James
![](https://secure.gravatar.com/avatar/3c4988f83703127d279406fc6eea7079.jpg?s=120&d=mm&r=g)
From an old thread[1]:
On Sat, 2005-06-11 at 11:35 -0400, Jp Calderone wrote:
I'm trying to diagnose an intermittent pausing problem on Win32, and t.i.process is unavailable on that platform, which reapChildren() relies on. Is there no need for this approach when launching the reactor with installSignalHandlers=0 on Windows? Steve [1]http://twistedmatrix.com/pipermail/twisted-python/2005-June/010692.html
![](https://secure.gravatar.com/avatar/15fa47f2847592672210af8a25cd1f34.jpg?s=120&d=mm&r=g)
On Jun 11, 2005, at 11:08 AM, Matt Feifarek wrote:
There is one. It logs "spawnProcess called, but the SIGCHLD handler is not installed. This probably means you have not yet called reactor.run, or called reactor.run(installSignalHandler=0). You will probably never see this process finish, and it may become a zombie process." However, your example doesn't have logging setup, so you don't see that message.
If you cannot override the signal handling, do something like: from twisted.internet import task task.LoopingCall(process.reapAllProcesses).start(1.0, now=False) That's less efficient but will work. I have a vague recollection that in old versions twisted used to do this by default but I might just be making that up. James
participants (6)
-
Glyph Lefkowitz
-
Itamar Shtull-Trauring
-
James Y Knight
-
Jp Calderone
-
Matt Feifarek
-
Steve Freitas