-
Notifications
You must be signed in to change notification settings - Fork 41
Description
I am combining multiple streams with a merge. The output of this stream is a summary "state" of a system. I.e. each item from the stream is a summary of the state of a system at that point in time. The resulting output is fed into a websocket and used to drive a react app. This react app then shows a handy live updating dashboard. This is working really well, but in the more extreme cases i don't really want to send 100's of events a second down the websocket, so i thought a throttle operator would be a handy tool to have in my belt.
The requirement is to start a timer when an item is received from the source, carry on iterating and when that timer expires only send the most recently received item from the source. And the timer should not be running unless there are 1 or more events waiting to send.
My poc looks like this:
@operator(pipable=True)
async def throttle(source, delay=0.5):
async with streamcontext(source) as streamer:
cur = None
next = asyncio.create_task(aiostream.aiter_utils.anext(streamer))
waiter = None
aws = {next}
while True:
done, aws = await asyncio.wait(aws, return_when=asyncio.FIRST_COMPLETED)
if next in done:
cur = await next
next = asyncio.create_task(aiostream.aiter_utils.anext(streamer))
aws.add(next)
if not waiter:
waiter = asyncio.create_task(asyncio.sleep(delay))
aws.add(waiter)
if waiter and waiter in done:
yield cur
waiter = NoneIt works, but it feels like its relying on asyncio primitives too much, and that maybe there is a more idiomatic way to do it with aiostream. Can you think of any cleaner ways to implement this. The calls to anext() especially make me feel like i've overlooked something.