How to forcefully close an async generator?

You can use a timeout on the queue so is_connected() is polled regularly if there is no item to pop:

async def event_publisher(connection, queue):
    while True:
        if not await connection.is_disconnected():
            try:
                event = await asyncio.wait_for(queue.get(), timeout=10.0)
            except asyncio.TimeoutError:
                continue
            yield event
        else:
            return

Alternatively, it is possible to use Queue.get_nowait().


It seems to be related to this issue. Noticable:

As shown in https://gist.github.com/1st1/d9860cbf6fe2e5d243e695809aea674c, it's an error to close a synchronous generator while it is being iterated.

...

In 3.8, calling "aclose()" can crash with a RuntimeError. It's no longer possible to reliably cancel a running asynchrounous generator.

Well, since we can't cancel running asynchrounous generator, let's try to cancel its running.

import asyncio
from contextlib import suppress


async def cancel_gen(agen):
    task = asyncio.create_task(agen.__anext__())
    task.cancel()
    with suppress(asyncio.CancelledError):
        await task
    await agen.aclose()  # probably a good idea, 
                         # but if you'll be getting errors, try to comment this line

...

if connection.is_disconnected():
    await cancel_gen(published_events)

Can't test if it'll work since you didn't provide reproducable example.