Qqwy

Qqwy

TypeCheck Core Team

When are Agent and Task.Supervisor useful?

I am working on a simple introduction talk to OTP. One of the things I myself am wondering about, however, is when Agent is useful and when Task.Supervisor is useful, as until now I’ve never felt the need to use them. So I am kind of searching for use-cases, so I can explain why they exist and when you should use them.

Agent

In the projects I have made in the past, I always wrapped a GenServer myself, instead of relying on Agent, because I knew that the message-passing and state-handling would become a little more complicated in the future. But I am not sure if this is the correct approach.

When is it better to use an Agent, and when is it better to just build a GenServer from scratch?

Task.Supervisor

I have used a lot of Tasks to enable small pieces of code that do not depend on each other to run concurrently. However, I’ve never had the need to supervise them, because they are either linked to the process that started them when using Task.async (so if a task fails, that process and all other tasks fail), or they were run with Task.start when I did not care about the return result, and therefore also did not care about if it succeeded or not.

In what cases is supervising tasks useful?

Most Liked

sasajuric

sasajuric

Author of Elixir In Action

A frequently overlooked but important role of supervisors is proper cleanup of processes. When a supervisor terminates, all of it’s descendants will be taken down as well. That allows you to terminate needless processes if some part of the system crashes, and also to cleanly take down the entire application (for example during rolling upgrade).

Therefore every process in your system should reside in the supervision tree, even if you don’t want to restart them. In such cases you can use the temporary restart strategy which is in fact the default for Task.Supervisor.

Except for some temporary experiments I wouldn’t advise using Task.start (or GenServer.start) in production as that may lead to dangling processes which may in turn cause some strange behaviour of the system.

25
Post #4
gausby

gausby

As you may know, processes can do pure state (Agent), or pure computation (Task)—and everything in between! (GenServer, :gen_fsm).

When I poke around in a code base and I see a process that uses Agent instead of GenServer, I will instantly know that this is all about state. If I see a :gen_fsm I will know it is all about state, and when I see a GenServer I will have to take a closer look.

The tasks are for one off computations.

I am not an expert on the Task.Supervisor—because I don’t use tasks that often myself—but I guess you use it in situations where you would want your process to start the computation, and said computation should restart if it fails, but you don’t want your process to die along the computation if it should fail. Sometimes you might want to kill your process along with the task, so spawning and linking within the process would work in that scenario, but otherwise: stick it in a supervision tree.

Notice; Task, Agent, :gen_fsm are all implemented using GenServer; so yeah, you could go through life using only GenServer—but you probably shouldn’t :slight_smile:

entone

entone

I use Task.Supervisor to handle incoming Datagrams for my UDP server. As a binary message comes in, it spawns a Task to process the datagram, if the decryption fails, or json parsing fails, no big deal, UDP server is still running.

Handling incoming datagrams…

And the supervisor…

defoemark

defoemark

AFAIK Agent is a “type” of GenServer created specifically for storing “shared” state, since in Elixir everything is isolated, I guess one would use it for storing live, quickly updating information.
Task.Supervisor can be used as a worker and it was designed to supervise Tasks, if you don’t want them to be linked to another process and you want to define different strategy. I’m personally using it for sending email messages or push notifications, basically the activity which is not critical for the business logic and can be run in background.

JEG2

JEG2

Author of Designing Elixir Systems with OTP

One thought I’ve had about this is that a supervised Task seems perfect for any processing that doesn’t involve explicitly receiving messages.

Task.Supervisor makes it handy to kick off such jobs as needed and it allows me to do things like retry in the case of transient errors, but not if the process exits normally.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement