Question

My setup has a Node.js child spawned which creates a 2-way ZeroRPC pair of sessions with a Python object.

The python side is similar to this:

class MyClass:
    def __init__(self, socketpath):
        self.client = zerorpc.Client()
        self.client.connect(socketpath)

    def sendtoclient(self, msg):
        self.client.receiveMessage(msg)

if __name__ == '__main__':
    zpc = zerorpc.Server(MyClass(sys.argv[1]))
    zpc.bind(sys.argv[1] + "_python")
    zpc.run()

The Node.js child client can invoke methods on the Python server, but the client within that server cannot invoke on the Node.js child server without getting an exception:

Traceback (most recent call last):
File "/usr/lib64/python2.6/site-packages/gevent/queue.py", line 271, in _unlock getter.switch(getter)

File "/usr/lib64/python2.6/site-packages/gevent/hub.py", line 534, in switch assert getcurrent() is self.hub, "Can only use Waiter.switch method from the Hub greenlet"

AssertionError: Can only use Waiter.switch method from the Hub greenlet
<callback at 0x3055e90 args=()> failed with AssertionError

Does the client in the Python class need to be spawned as a gevent and then its receiveMessage method invoked when needed? Or is there some other trick I'm overlooking?

Was it helpful?

Solution

After some experimenting, a workable solution came from some examples in Gevent's documentation. The solution I went with is to create a gevent Queue that is populated from the server side and output from a separate Greenlet in a loop. So in the file with my server, I added:

import gevent
from gevent.queue import Queue, Empty

messagesOut = Queue()
def clientWorker(address):
    client = zerorpc.Client()
    if (None != client):
        client.connect(address)
        while True:
            try:
                messages = messagesOut.get()
                client.passMessages(messages) # a method on the Node.js-side ZeroRPC server
            except: # Empty could be thrown here if you're interested
                pass
            finally:
                gevent.sleep(0)

In MyClass, its initialization changed to retain a reference to the queue as self.outbox (indeed, I could have used global each time I access it). When an async message needs to be sent, MyClass calls self.outbox.put(messages).

Then down below when the ZeroRPC instances are created, I spawned each:

if __name__ == '__main__':
    ge_client = gevent.spawn(clientWorker, sys.argv[1] + "_node2python")
    zpc = zerorpc.Server(messagesOut)
    zpc.bind(sys.argv[1] + "_python2node")
    ge_server = gevent.spawn(zpc.run)
    gevent.joinall([ge_client, ge_server]) # up and running here.

Doing the above resolved my problems as a proof-of-concept.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top