Archived

This forum has been archived. Please start a new discussion on GitHub.

Ice.Application and Twisted reactor loop signal handling. (Python)

Hi, I'm working on a project where the twisted web socket server needs access to an ice proxy object 'meta' that is created in the Ice.Application run method. Currently I'm starting the twisted reactor at the bottom of the run method and passing the meta object to the web socket factory.

The problem: Both Ice.Application and the Twisted reactor are built to handle signals and shutdown cleanly. However, when I start my application I see six processes in htop (I assume one for Twisted and the rest for the Ice runtime?). When I send a SIGINT or Ctrl-C Ice will destroy the communicator but the Twisted reactor stays running and there are still two processes remaining. I then have to send a SIGTERM to get them to close. If I run either Ice or Twisted independently, they are both able to handle SIGINT.

What would I need to do so that both Ice and Twisted can respond to signals such as SIGINT? Am I doing something incorrectly in this code, or is this a different kind of problem?
from __future__ import print_function, division
import sys

# third party imports
import Ice

from twisted.python import log
from twisted.internet import reactor

from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory

# compiled Murmur.ice
import Murmur


class Callback:
    def __init__(self, web_socket_instance):
        self.web_socket_instance = web_socket_instance

    def response(self, result):
        result = str(result).encode('utf8')
        self.web_socket_instance.sendMessage(result)

    def exception(self, ex):
        ex = str(ex).encode('utf8')
        self.web_socket_instance.sendMessage(ex)


class ServerProtocol(WebSocketServerProtocol):

    def onMessage(self, payload, isBinary):
        if isBinary:
            print("Binary message received: {0} bytes".format(len(payload)))
        else:
            msg = payload.decode('utf8')
            print("Text message received: {0}".format(msg))
            self._get_uptime()

    def _get_uptime(self):
        cb = Callback(self)
        self.factory.meta.begin_getUptime(cb.response, cb.exception)


class ServerFactory(WebSocketServerFactory):
    def __init__(self, url, meta, debug=False, debugCodePaths=False):
        WebSocketServerFactory.__init__(self, url, debug=debug, debugCodePaths=debugCodePaths)
        self.meta = meta


class IceClient(Ice.Application):
    def run(self, args):
        self.destroyOnInterrupt()

        self.communicator().getImplicitContext().put("secret", "****************")

        server_host = 'localhost'
        server_port = '6502'

        proxy_str = 'Meta:default -h {} -p {}'.format(server_host, server_port)

        meta = Murmur.MetaPrx.checkedCast(
            self.communicator().stringToProxy(proxy_str))

        factory = ServerFactory("ws://localhost:9000", meta)
        factory.protocol = ServerProtocol

        reactor.listenTCP(9000, factory)
        reactor.run()

        return 0


if __name__ == '__main__':
    log.startLogging(sys.stdout)

    ice_app = IceClient()
    ice_app.main(sys.argv, "config.client")

Comments

  • matthew
    matthew NL, Canada
    Ice.Application is a helper class and not required. Since in your case it is getting in the way, I'd suggest not using it. To get an idea of what is required take a look at the minimal demo, or the Ice.Application source itself.
  • Thanks for your response Matthew. I know Ice.Application is a helper class, but I thought I should ask to make sure there wasn't anything I could be doing differently before I decided not to use it. Thanks for your suggestion, I'll see what I can come up with without the helper class.