Skip to content

[Bug]: HttpStream race condition in close() — final message can be sent before in-flight chunks complete #418

Description

@corinagum

Bug Description

HttpStream (packages/apps/src/microsoft_teams/apps/http_stream.py) has a race condition: close() can send the final message while _flush() is still awaiting in-flight _send_activity() calls. This causes the final stream message to arrive before intermediate chunks finish sending.

This is the Python parity of microsoft/teams.ts#549, fixed in microsoft/teams.ts#553. Note: the TS issue's "Bug 1" (streamType override) does not affect Python — close() already calls with_channel_data() before add_stream_final(), which is the correct order.

Root cause

_wait_for_id_and_queue() polls:

while (self._queue or not self._id) and not self._canceled:
    await self._state_changed.wait()
    self._state_changed.clear()

This checks the queue and _id but not whether _flush() is currently holding self._lock. Inside _flush(), the inner while self._queue loop drains the queue before the awaited _send_activity(...) calls run. While those awaits are pending:

  • self._queue is empty
  • self._id is set (after the first chunk completes)
  • self._lock is still held

close() sees its predicate become false, exits the wait, and proceeds to send the final activity — racing the in-flight chunk send.

Reproduction

stream.emit('chunk 1')
stream.emit('chunk 2')
await stream.close()
# close() may send final message before chunk 2 finishes sending

Proposed fix

Add self._lock.locked() to the predicate in _wait_for_id_and_queue(). The lock primitive is already used elsewhere in close() (line 157 early-return checks self._lock.locked()).

I have a fix and unit test ready to submit as a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions