Manage a Series of Tasks

Pressure on the system

Let’s imagine we have one million users, and want to send an email to all of them. We can use Enum.map/2 and Task.async/1 as before.

Start one million processes

Starting one million processes will put sudden pressure on our system resources. It can degrade the system’s performance and potentially make other services unresponsive. Our email service provider will not be happy either, since we also put a lot of pressure on their email infrastructure.

Start processes one by one

If we send emails one by one, it will be slow and inefficient. It seems that we are at a crossroads, and whichever way we take, we end up in peril. We don’t want to choose between performance and reliability. We want to run Task processes to leverage concurrency but also ensure we do not overload our system resources as we scale our product and increase our user base.

Solution

The solution to our problems is another convenient function from the Task module, async_stream. The async_stream function is designed to create task processes from a list of items. For every item in the list, async_stream/3 starts a process and runs the function we provide to process the item. It works just like Enum.map/2 and Task.async/2 combined, with one major difference: we can set a limit on the number of processes running at the same time. The figure below illustrates how this works:

Get hands-on with 1200+ tech skills courses.