How to persist websocket connection in sanic

Hello, this is the first time I have used sanic on a company project, the sanic framework is very good!

Now I have a problem. I want to persist a websocket connection,in order to send request to operator websocket to send messages. When workers=1, I can get the value, but when workers>1, I often can’t get it. I guess it may be that different workers do not share these variables. , So is there any way I can get the value when worker>1 ?looking forward to your answers

this my some codes

@app.get("/send_msg/<msg:str>")
async def send_msg(request, msg: str):
    await app.ctx.current_ws.send(msg)
    return json({"code": 200, "msg": "success"})

@app.websocket("/feed")
async def feed(request, ws):
    app.ctx.current_ws = ws
    while True:
        data = "hello!"
        print("Sending: " + data)
        await ws.send(data)
        data = await ws.recv()
        print("Received: " + data)

when I send request http://127.0.0.1/send_msg/something, many time it show “AttributeError: ‘types.SimpleNamespace’ object has no attribute ‘current_ws’”,some time ok

Hi :wave:
Thank you very much.

Unfortunately to do what you want will be a little more complicated. You are correct, you see that behavior because values are not shared across multiple workers. This is a limitation of working with multiprocessing. To get around this you need a more robust solution.

Besides not sharing data, the other problem with your solution is what happens if there are multiple simultaneous connections? One would overwrite the other.

So, implementation I suppose will change depending upon whether the call with the send() should send to one specific ws, or all connected clients.

You will want to use something like redis pubsub to pass messages to your websockets. The handler creates a bg task to consume messages from the pubsub and send when it receives one, then it needs to also be ready to consume incoming messages from the client.

Your send_msg endpoint (which I’d suggest making POST and not GET) should publish a message to the pubsub.

Take a look at this How to use redis pubsub with sanic websocket? - #2 by ahopkins

@ahopkins Thank you for your help, I would like to ask if sanic can use shared dict to share data among multiple workers like openresty

I am not familiar with that project so I cannot say. If you specifically mean any one of the shared data types, then the answer is unfortunately no since they would need to be created at the time of the subprocess. This is not a feature that will be added to Sanic because it is a very small use case and really prohibits the scalability of applications.

One of the cornerstones of the project is that it needs to be scalable. Using shared memory is not, because even though it allows for scaling processes, it still would be limited to a single machine. Therefore, Sanic would encourage use of a shared data service for state management. This is a much more common practice with web development and allows for a greater horizontal scalability.

This is why I suggest redis because it is very simple to run and integrate.

thanks a lot,I know it