Websocket with Nameko

Hello,
I wanted to implement a websocket server, which listens for rpc calls using nameko.
The primary aim is to emit events on the websocket connections, after an rpc is called in the same implementation.
I went through the test websocket code.
The problem I am facing is, the websocket hub is redifinig “rpc” in its class.
Now, I am able to spawn a websocket, and also receive events from the html example code.

But I want rpc calls (implemented on the websocket server side), to be called from the backed, and emit events to the frontend (html client).

I am not able to figure out how to implement these RPC calls, as normally I would use nameko.rpc, but here the rpc is overloaded by the websocket hub.

Ideally I want something like this:

{Browser based Web socket client}<—> {Nameko WS server + RPC server}<— {Backend Nameko RPC
Client}

Any pointers would help.

Hi @rarindam,

Can you share a code sample to understand exactly your problem. In any case, if it’s just a problem of redefining “rpc”, why don’t you just import on service file, websocket rpc as ws_rpc or something else just to avoid shadowing of rpc. Something like that:

from nameko.rpc import rpc
from nameko.web.websocket import rpc as ws_rpc

Hi,
Thank you for replying.

  1. I tried that route. Issue is the following:
    a. Using a combination of standard python Websocket, along with nameko, needs the usage of monekypatches. When doing this, the standard websocket fails. The nameko rpc calls work.

  2. I found out the solution is to use Nameko’s own websockethub implementation. In this way I am using nameko runtime, and its own websocket implementation, which is fine and seems to work.

from nameko.web.websocket import WebSocketHubProvider, rpc
from nameko.events import event_handler
class WebsocketService(object):
name = “websockets”

container_id = ContainerIdentifier()
websocket_hub = WebSocketHubProvider()

@event_handler("event_listener", "evt_received")
def handle_event(self, payload):
    self.websocket_hub.broadcast('test_channel', 'ping', {
        'value': "payload {} from {}".format(payload, self.container_id),
    })
  1. Another way of achieving the same is to use combination of python websockets and kombo messaging:

from kombu import Exchange, Queue
from nameko.messaging import Publisher, consume
MY_ROUTING_KEY = “my_routing_key”
my_exchange = Exchange(name=“my_exchange”)

my_queue = Queue(exchange=my_exchange, routing_key=MY_ROUTING_KEY, name=MY_ROUTING_KEY)
@consume(queue=my_queue)
def update_ws(self, payload):
self.websocket_hub.broadcast(‘test_channel’, ‘ping’, {
‘value’: “payload {} from {}”.format(payload, self.container_id),
})

Hi @rarindam,

I am glad to hear that you found a way to achieve your goal.

I have followed many times option (2) and it has worked me well.

Finally the only tricky part is that you need to implement websocket heartbeat , especially if your nameko service gets deployed behind a reverse proxy like nginx.