forked from goodboy/tractor
1
0
Fork 0

Add internal msg stream backpressure controls

In preparation for supporting both backpressure detection (through an
optional error) as well as control over the msg channel buffer size, add
internal configuration flags for both to contexts. Also adjust
`Context._err_on_from_remote_msg()` -> `._maybe..` such that it can be
called and will only raise if a scope nursery has been set. Add
a `Context._error` for stashing the remote task's error that may be
delivered in an `'error'` message.
stricter_context_starting
Tyler Goodlet 2021-12-05 19:19:53 -05:00
parent 6751349987
commit 92b540d518
1 changed files with 24 additions and 9 deletions

View File

@ -190,7 +190,8 @@ class ReceiveMsgStream(trio.abc.ReceiveChannel):
# was it shouldn't matter since it's unlikely a user
# will try to re-use a stream after attemping to close
# it).
await self._ctx.send_stop()
with trio.CancelScope(shield=True):
await self._ctx.send_stop()
except (
trio.BrokenResourceError,
@ -283,11 +284,11 @@ class ReceiveMsgStream(trio.abc.ReceiveChannel):
class MsgStream(ReceiveMsgStream, trio.abc.Channel):
"""
'''
Bidirectional message stream for use within an inter-actor actor
``Context```.
"""
'''
async def send(
self,
data: Any
@ -297,6 +298,8 @@ class MsgStream(ReceiveMsgStream, trio.abc.Channel):
'''
# if self._eoc:
# raise trio.ClosedResourceError('This stream is already ded')
# if self._ctx._error:
# raise self._ctx._error
await self._ctx.chan.send({'yield': data, 'cid': self._ctx.cid})
@ -330,6 +333,7 @@ class Context:
# only set on the caller side
_portal: Optional['Portal'] = None # type: ignore # noqa
_result: Optional[Any] = False
_error: Optional[BaseException] = None
# status flags
_cancel_called: bool = False
@ -340,6 +344,8 @@ class Context:
# only set on the callee side
_scope_nursery: Optional[trio.Nursery] = None
_backpressure: bool = False
async def send_yield(self, data: Any) -> None:
warnings.warn(
@ -353,23 +359,28 @@ class Context:
async def send_stop(self) -> None:
await self.chan.send({'stop': True, 'cid': self.cid})
def _error_from_remote_msg(
def _maybe_error_from_remote_msg(
self,
msg: Dict[str, Any],
) -> None:
'''Unpack and raise a msg error into the local scope
'''
Unpack and raise a msg error into the local scope
nursery for this context.
Acts as a form of "relay" for a remote error raised
in the corresponding remote callee task.
'''
assert self._scope_nursery
self._error = unpack_error(msg, self.chan)
async def raiser():
raise unpack_error(msg, self.chan)
if self._scope_nursery:
self._scope_nursery.start_soon(raiser)
async def raiser():
__tracebackhide__ = True
raise self._error
if not self._scope_nursery.cancel_scope.cancel_called:
self._scope_nursery.start_soon(raiser)
async def cancel(self) -> None:
'''Cancel this inter-actor-task context.
@ -433,6 +444,8 @@ class Context:
async def open_stream(
self,
backpressure: bool = False,
msg_buffer_size: Optional[int] = None,
) -> AsyncGenerator[MsgStream, None]:
'''
@ -482,7 +495,9 @@ class Context:
ctx = actor.get_context(
self.chan,
self.cid,
msg_buffer_size=msg_buffer_size,
)
ctx._backpressure = backpressure
assert ctx is self
# XXX: If the underlying channel feeder receive mem chan has