Source code for action0.pipeline.buffer
"""
The buffer that hands items from one pipeline step to the next.
"""
from typing import Protocol
from typing import runtime_checkable
[docs]
@runtime_checkable
class Buffer[Item](Protocol):
"""
The slice of :py:class:`asyncio.Queue` a pipeline needs between two steps.
:py:class:`asyncio.Queue` satisfies this protocol as it is, which is why the
pipeline creates plain queues when no buffer is supplied. Implement the protocol
yourself to buffer somewhere other than the event loop's memory.
Implementations **must** reproduce the queue's shutdown semantics, because the
pipeline detects "this stage has run dry" from them and nothing else:
- after :py:meth:`shutdown`, :py:meth:`put` raises
:py:exc:`asyncio.QueueShutDown` right away,
- :py:meth:`get` raises :py:exc:`asyncio.QueueShutDown` once the items still
buffered have been handed out — or immediately, when shut down with
``immediate=True``.
A bounded buffer is what applies backpressure: while it is full, the producing
step's workers wait in :py:meth:`put` instead of reading more input.
"""
[docs]
def qsize(self) -> int:
"""
:return: the number of items currently buffered.
"""
...
[docs]
async def put(self, item: Item) -> None:
"""
Append an item, waiting while the buffer is full.
:param item: the item to buffer.
:raises asyncio.QueueShutDown: if the buffer has been shut down.
"""
...
[docs]
async def get(self) -> Item:
"""
Take the oldest buffered item, waiting while the buffer is empty.
:return: the item.
:raises asyncio.QueueShutDown: if the buffer is shut down and drained.
"""
...
[docs]
def shutdown(self, immediate: bool = False) -> None:
"""
Signal that no more items will be added.
:param immediate: also discard the items still buffered, so that waiting
consumers stop right away instead of draining first.
"""
...