Twisted reactor is stopped, but program doesn't end?
Question: So I'm writing a small script to use with Deluge. Deluge uses Twisted, and I
really don't have a firm grasp on how it works. Normally I'd just look up more
info on it, but getting started with Twisted would take a _long_ time and is
beyond the scope of this little project. So I figured I would just ask here.

Now, I have this code. I'll try to explain the specifig parts I need help with

    
    
    import base64
    
    import processargs
    
    from deluge.ui.client import client
    from twisted.internet import reactor
    
    from deluge.log import setupLogger
    setupLogger()
    
    options = processargs.readConfig(os.path.expanduser("~/.deluge-automator"))
    
    d = client.connect(
        host=options['host'],
        port=int(options['port']),
        username=options['username'],
        password=options['password']
    )
    
    def start():
        #other code
    
        t = client.core.add_torrent_file(tfile,
                                         base64.encodestring(data), None)
    
        t.addCallback(on_torrent_added_success, tfile)
        t.addErrback(on_torrent_added_fail)
    
    
    def handle_stop_signal(SIGNAL, stack):
        client.disconnect()
        reactor.stop()
    
    
    def on_torrent_added_success(result, tfile):
        #other code
        start()
    
    
    def on_torrent_added_fail(result):
        print "Add torrent failed!"
        print "result: ", result
    
    
    def on_connect_success(result):
        #other code
        start()
    
    
    d.addCallback(on_connect_success)
    
    
    def on_connect_fail(result):
        print "Connection failed!"
        print "result: ", result
    
    
    d.addErrback(on_connect_fail)
    
    signal.signal(signal.SIGTERM, handle_stop_signal)
    signal.signal(signal.SIGINT, handle_stop_signal)
    
    reactor.run()
    

When a torrent is successfully added, it should go back to start(), and it
does, but I think it loses the reactor or something. Because now whenever it
recieves a SIGTERM or SIGINT, the reactor closes, but doesn't quit the
program:

    
    
    ± % python2 main.py
    Connection was successful!
    result:  10
    ^C^CConnection failed!
    result:  [Failure instance: Traceback: <class 'twisted.internet.error.ReactorNotRunning'>: Can't stop reactor that isn't running.
    /usr/lib/python2.7/site-packages/twisted/internet/defer.py:551:_runCallbacks
    /usr/lib/python2.7/site-packages/deluge/ui/client.py:412:__on_login
    /usr/lib/python2.7/site-packages/twisted/internet/defer.py:368:callback
    /usr/lib/python2.7/site-packages/twisted/internet/defer.py:464:_startRunCallbacks
    --- <exception caught here> ---
    /usr/lib/python2.7/site-packages/twisted/internet/defer.py:551:_runCallbacks
    main.py:70:on_connect_success
    main.py:32:start
    main.py:49:handle_stop_signal
    /usr/lib/python2.7/site-packages/twisted/internet/base.py:577:stop
    ]
    

So the reactor gets stopped, but it doesn't quit the program. I have to
keyboard interrupt twice. Once to stop the reactor, and a second time to throw
the error. Is there a certain way to set up a loop like this?


Answer: reactor handles sigint, sigterm itself (there might be a parameter of
`reactor.run()` that disables that). Install
`reactor.addSystemEventTrigger('before', 'shutdown', client.disconnect)`
instead.

See [twisted: catch keyboardinterrupt and shutdown
properly](http://stackoverflow.com/q/3453451/4279).

