0

i created a simple websocket server using aiohttp . my server reads message from redis pub/sub and sends it to client . this is my websocket code:

import aiohttp
from aiohttp import web
import aioredis


router = web.RouteTableDef()

@router.get("/ws")
async def websocket_handler(request):

    ws = web.WebSocketResponse()
    await ws.prepare(request)
    sub = request.config_dict["REDIS"]
    ch, *_ = await sub.subscribe('hi')

    async for msg in ch.iter(encoding='utf-8'):
        await ws.send_str('{}: {}'.format(ch.name, msg))

async def init_redis(app):
    redis_pool = await aioredis.create_redis_pool('redis://localhost')
    app["REDIS"] = redis_pool
    yield
    redis_pool.close()
    await redis_pool.wait_closed()



async def init_app():
    app = web.Application()
    app.add_routes(router)
    app.cleanup_ctx.append(init_redis)
    return app


web.run_app(init_app())

my first client can connect to server and receive messages but when i create another client to connect to this endpoint it receive no messages ! what is the problem ? how can i fix this problem?

Shoobi
  • 88
  • 1
  • 10

1 Answers1

1

You need to call create_redis for each client and publish the message to the channel. Otherwise, only the first client will receive the subscribed message. So, you can edit your code as follows.

import aiohttp
from aiohttp import web
import aioredis
import asyncio

router = web.RouteTableDef()


async def reader(ws, ch):
    while (await ch.wait_message()):
        await ws.send_str('{}: {}'.format(ch.name, msg))


@router.get("/ws")
async def websocket_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    sub = await aioredis.create_redis_pool('redis://localhost')
    pub = await aioredis.create_redis_pool('redis://localhost')
    
    ch, *_ = await sub.subscribe('hi')

    asyncio.ensure_future(reader(ws, ch))
    async for msg in ws:
        await pub.publish('hi', msg)

    sub.close()
    pub.close()


async def init_app():
    app = web.Application()
    app.add_routes(router)
    return app


web.run_app(init_app())

Please note there may be minor syntax error (e.g. format of the message), but this is the structure that you should follow as it worked for me. I got it to work with my application.

F.H.
  • 1,456
  • 1
  • 20
  • 34
noninertialframe
  • 568
  • 1
  • 10
  • 24