Cómo ejecutar una (o varias) funciones periódicas en un servidor Ice.

Crear un servidor Ice es muy fácil con ayuda de la clase Ice.Application. El communicator() corre en un hilo distinto dejando libre el flujo actual para realizar otras tareas. Lo habitual después de configurar el adaptador y arrancar el comunicador, es invocar el método waitForShutdown() en espera de que el servidor acabe. Este es un servidor mínimo en Python aplicando esa idea:

import sys, Ice

class Hello(Ice.Object):
    def ice_ping(self, current=None):
        print "ping()"

class Server(Ice.Application):
    def run(self, argv):
        adapter = self.communicator().\
                  createObjectAdapterWithEndpoints("Server", "default -p 9999")

        adapter.add(Hello(), Ice.stringToIdentity("Hello"))
        adapter.activate()

        self.shutdownOnInterrupt()
        self.communicator().waitForShutdown()            
        return 0

sys.exit(Server().main(sys.argv))

A efectos de pruebas, el cliente sería:

import sys, Ice

class Client (Ice.Application):
    def run(self, argv):
        base = self.communicator().stringToProxy("Hello:default -p 9999")
        base.ice_ping()
        return 0

sys.exit(Client().main(sys.argv))

Ahora imagina que, en el servidor, necesitas ejecutar un método cada 2 segundos. Una forma sencilla es utilizar el bucle de eventos de gobject, es decir, algo como lo siguiente (sólo pongo la clase Server):

class Server(Ice.Application):
    def run(self, argv):
        adapter = self.communicator().\
                  createObjectAdapterWithEndpoints("Server", "default -p 9999")

        adapter.add(HelloI(), Ice.stringToIdentity("Hello"))
        adapter.activate()

        self.shutdownOnInterrupt()

        gobject.threads_init()
        gobject.timeout_add(2000, self.event)
        self.loop = gobject.MainLoop()
        self.loop.run()

        return 0

    def event(self):
        print 'Event!'
        return True

Y esto funciona bien salvo por una pequeña pero desesperante cuestión: el programa no se cierra al pulsar Ctrl-C. Para arreglarlo, parece que lo más sencillo es usar otro método de Ice.Applicacion llamado callbackOnInterrupt() que provoca la ejecución del método especial interruptCallback() cuando se produce alguna de las señales prefijadas. Se puede aprovechar la ejecución de ese método para terminar el bucle de eventos de gobject. De tal modo que el servidor quedaría algo como:

class Server(Ice.Application):
    def run(self, argv):
        adapter = self.communicator().\
                  createObjectAdapterWithEndpoints("Server", "default -p 9999")

        adapter.add(HelloI(), Ice.stringToIdentity("Hello"))
        adapter.activate()

        self.callbackOnInterrupt()

        gobject.threads_init()
        gobject.timeout_add(2000, self.event)
        self.loop = gobject.MainLoop()
        self.loop.run()

        self.communicator().shutdown()
        return 0

    def interruptCallback(self, args):
        gobject.idle_add(self.loop.quit)

    def event(self):
        print 'Event!'
        return True

En la próxima entrega, lo mismo, pero en C++…



blog comments powered by Disqus