Skip to content

Commit 94e5c7d

Browse files
transport: call Protocol.connection_made ASAP
It's been observed that in certain real-life scenarios we can start receiving data via `.pipe_data_received()` before `.subprocess_exec()` completes. That happens when there are enough async callbacks in flight that the spawned subprocess starts writing to its stdout before we have a chance to deliver the result of `.subprocess_exec()`. This is problematic, because we were deferring calling the `.connection_made()` of our connected Protocol until after the exec call returned. This gap made it possible for us to start delivering data to the Protocol before connecting to it. Instead of waiting for the async exec call to finish running, call connection_made() on the Protocol as soon as our own connection_made() is called. There was really no reason not to do it that way in the first place — and the assumption that it was equivalent to calling it at the end of `.connection_made()` proved incorrect.
1 parent a9c9538 commit 94e5c7d

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

src/ferny/transport.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,8 @@ def exec_completed(task: asyncio.Task) -> None:
153153
assert self._stdin_transport is not None
154154
assert self._stdout_transport is not None
155155

156-
# Time to go live — ask the InteractionAgent to start processing
157-
# stderr and tell our protocol that we're ready to receive data.
156+
# Ask the InteractionAgent to start processing stderr.
158157
self._agent.start()
159-
logger.debug('calling connection_made(%r, %r)', self, self._protocol)
160-
self._protocol.connection_made(self)
161158

162159
self._exec_task.add_done_callback(exec_completed)
163160

@@ -239,6 +236,9 @@ def connection_made(self, transport: asyncio.BaseTransport) -> None:
239236
stderr_transport = transport.get_pipe_transport(2)
240237
assert stderr_transport is None
241238

239+
logger.debug('calling connection_made(%r, %r)', self, self._protocol)
240+
self._protocol.connection_made(self)
241+
242242
def connection_lost(self, exc: 'Exception | None') -> None:
243243
logger.debug('connection_lost(%r, %r)', self, exc)
244244
if self._exception is None:

0 commit comments

Comments
 (0)