Reputation: 335
I have an issue with my (dockerized) application consuming an ever increasing amount of memory until the Linux kernel kills is. In the container's docker logs
I only got an ominous Killed
message without further context - only after checking the kernel logs (cat /var/log/kern.log
) and docker stats
did I realize what was happening - memory usage was going up by ~10MB per second.
The application is an asyncronous grpc
-server with several concurrent tasks (using return ensure_future(self._continuous_function)
to keep the function's task up and running, async so the server endpoints are not blocked).
Upvotes: 2
Views: 7940
Reputation: 1719
You could schedule a task in following way this way you can ensure that the task cleanup after itself.
import asyncio
from typing import Coroutine
from marie.helper import get_or_reuse_loop
background_tasks = set()
def run_background_task(coroutine: Coroutine) -> asyncio.Task:
"""Schedule a task reliably to the event loop.
This API is used when you don't want to cache the reference of `asyncio.Task`.
For example,
```
get_event_loop().create_task(coroutine(*args))
```
The above code doesn't guarantee to schedule the coroutine to the event loops
When using create_task in a "fire and forget" way, we should keep the references
alive for the reliable execution. This API is used to fire and forget
asynchronous execution.
https://docs.python.org/3/library/asyncio-task.html#creating-tasks
"""
task = get_or_reuse_loop().create_task(coroutine)
# Add task to the set. This creates a strong reference.
background_tasks.add(task)
# To prevent keeping references to finished tasks forever,
# make each task remove its own reference from the set after
# completion:
task.add_done_callback(background_tasks.discard)
return task
Upvotes: 0
Reputation: 335
I figured out that ensure_future()
caused my memory leak issue - or rather the return
I used with it. Apparently the return meant that a reference to the original task was being kept in memory (instead of being garbage collected), and the function only had a very short wait time associated with it (1ms) - so memory kept building up fast.
So after removing the leak my app now consumes about 60MB of very constant memory. I hope this helps somebody else out, I couldn't find a reference to this exact issue which is why I'm sharing it here.
Upvotes: 4