AsyncIO: avoid holding exceptions and traceback #806
+72
−21
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.



More complete and reasonable fix for the problem I described in #802.
Problem description
In situations with lot of tasks being executed, and some of them raising exceptions with large tracebacks, we might encounter huge spikes in memory consumption that might lead to OOM issues. Mainly, this is because the garbage collector may not run timely enough under high pressure. In a sense, this is similar to the old issue #351.
The problem has several sources:
dramatiq/dramatiq/asyncio.py
Lines 137 to 141 in aa91cdf
dramatiq/dramatiq/asyncio.py
Lines 143 to 149 in aa91cdf
Proposed solution
The solution is to make sure to detach the exception context from the coroutine and future so we can manually manage its lifecycle and force garbage collection. Basically, we use local variables to store the result and exception of the coroutine; instead of relying on
future.result()directly.Similar to #351, we manually call
gc.collect()after we handled the exception to make sure we clear it right away.I also added a unit test for this. Admittedly, it's a bit complex since it's hard to replicate this behaviour inside pytest with the stub broker.
Side note
The happy side-effect of this change is that it makes the TimeoutError fix (#791) a bit more readable, since we directly handle the
TimeoutErrorraised inside the coroutine.