File tree Expand file tree Collapse file tree 1 file changed +33
-0
lines changed Expand file tree Collapse file tree 1 file changed +33
-0
lines changed Original file line number Diff line number Diff line change @@ -164,3 +164,36 @@ class User:
164164Replacing ` assert ` statements with ` raise AssertionError(...) ` (or whatever
165165exception class you prefer) ensures that these checks cannot be trivially
166166disabled.
167+
168+
169+ ## Fire and forget async context blocks
170+
171+ When writing asyncio-based async context blocks (i.e. using async context managers), we sometimes
172+ fail to continuously check that the background task started is still running. For example, the
173+ following is how our Connection service was implemented
174+ (https://github.com/ethereum/trinity/blob/0db2a36706e5327fa040258bb5fef3fae75d9d8c/p2p/connection.py#L132-L153 )
175+ and since it doesn't perform any health checks on the multiplexing task running in the background,
176+ a crash in the multiplexer that failed to cancel the connection would leave the connection running
177+ forever.
178+
179+ ``` python
180+ async def run ():
181+ async with self ._multiplexer.multiplex():
182+ ...
183+ await self .manager.wait_finished()
184+ ```
185+
186+ In order to avoid this we need to make sure our async context managers always yield a reference
187+ to something that can be used to wait for (or check the state) of the background task. In the
188+ above example it could be something like:
189+
190+ ``` python
191+ async def run ():
192+ async with self ._multiplexer.multiplex() as multiplexing_task:
193+ ...
194+ await asyncio.wait(
195+ self .manager.wait_finished(), multiplexing_task,
196+ return_when = asyncio.FIST_COMPLETED )
197+ if multiplexing_task.done():
198+ self .manager.cancel()
199+ ```
You can’t perform that action at this time.
0 commit comments