Skip to content

Commit 7d5b616

Browse files
authored
Yield to give "synchronous" writes a chance to complete (#1388)
1 parent 9ffff88 commit 7d5b616

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

shiny/reactive/_reactives.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"event",
1616
)
1717

18+
import asyncio
1819
import functools
1920
import traceback
2021
import warnings
@@ -575,6 +576,10 @@ async def _run(self) -> None:
575576
try:
576577
with ctx():
577578
await self._fn()
579+
580+
# Yield so that messages can be sent to the client if necessary.
581+
# https://github.com/posit-dev/py-shiny/issues/1381
582+
await asyncio.sleep(0)
578583
except SilentException:
579584
# It's OK for SilentException to cause an Effect to stop running
580585
pass

shiny/session/_session.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
__all__ = ("Session", "Inputs", "Outputs")
66

7+
import asyncio
78
import contextlib
89
import dataclasses
910
import enum
@@ -653,6 +654,12 @@ def verify_state(expected_state: ConnectionState) -> None:
653654
f"Unrecognized method {message_obj['method']}"
654655
)
655656

657+
# Progress messages (of the "{binding: {id: xxx}}"" variety) may
658+
# have queued up at this point; let them drain before we send
659+
# the next message.
660+
# https://github.com/posit-dev/py-shiny/issues/1381
661+
await asyncio.sleep(0)
662+
656663
self._request_flush()
657664

658665
await flush()

tests/pytest/mocktime.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ async def _sleep(self, delay: float) -> None:
6767
self._i += 1
6868
# Oldest first
6969
self._sleepers.sort()
70+
71+
# This is necessary for some tests that call logic that internally awaits on
72+
# asyncio.sleep(0). Without this, they hang.
73+
#
74+
# Another potential workaround would've been to check if delay <= 0 and just
75+
# return. But this solution has the nice property of actually yielding control
76+
# (I think...!), which is the whole point of asyncio.sleep(0).
77+
if not self._is_advancing:
78+
await self.advance_time(0)
79+
7080
await wake.wait()
7181

7282

0 commit comments

Comments
 (0)