@@ -2,10 +2,10 @@ defmodule Task do
2
2
@ moduledoc """
3
3
Conveniences for spawning and awaiting for tasks.
4
4
5
- Tasks are processes that meant to execute one particular
6
- action throughout their life-cycle, often with little
7
- explicit communication with other processes. The most common
8
- use case for tasks is to compute a value asynchronously:
5
+ Tasks are processes meant to execute one particular
6
+ action throughout their life-cycle, often with little or no
7
+ communication with other processes. The most common use case
8
+ for tasks is to compute a value asynchronously:
9
9
10
10
task = Task.async(fn -> do_some_work() end)
11
11
res = do_some_other_work()
@@ -16,28 +16,21 @@ defmodule Task do
16
16
They are implemented by spawning a process that sends a message
17
17
to the caller once the given computation is performed.
18
18
19
- Besides `async/1` and `await/1`, tasks can also be used as part
20
- of supervision trees and dynamically spawned in remote nodes.
21
- We will explore all three scenarios next.
19
+ Besides `async/1` and `await/1`, tasks can also be used be
20
+ started as part of supervision trees and dynamically spawned
21
+ in remote nodes. We will explore all three scenarios next.
22
22
23
23
## async and await
24
24
25
25
The most common way to spawn a task is with `Task.async/1`. A new
26
- process will be created and this process is linked and monitored
27
- by the caller. However, the processes are unlinked right before
28
- the task finishes, allowing the proper error to be triggered only
29
- on `await/1`.
26
+ process will be created, linked and monitored by the caller. Once
27
+ the task action finishes, a message will be sent to the caller
28
+ with its result.
30
29
31
- This implies three things:
32
-
33
- 1) In case the caller crashes, the task will be killed and its
34
- computation will abort;
35
-
36
- 2) In case the task crashes due to an error, the parent will
37
- crash only on `await/1`;
38
-
39
- 3) In case the task crashes because a linked process caused
40
- it to crash, the parent will crash immediately;
30
+ `Task.await/1` is used to read the message sent by the task. On
31
+ await, Elixir will also setup a monitor to verify if the process
32
+ exited with any abnormal reason (or in case exits are being
33
+ trapped by the caller).
41
34
42
35
## Supervised tasks
43
36
@@ -55,14 +48,9 @@ defmodule Task do
55
48
]
56
49
57
50
Since such tasks are supervised and not directly linked to
58
- the caller, they cannot be awaited on. For such reason,
59
- differently from `async/1`, `start_link/1` returns `{:ok, pid}`
60
- (which is the result expected by supervision trees).
61
-
62
- Such tasks are useful as workers that run during your application
63
- life-cycle and rarely communicate with other workers. For example,
64
- a worker that pushes data to another server or a worker that consumes
65
- events from an event manager and writes it to a log file.
51
+ the caller, they cannot be awaited on. Note `start_link/1`,
52
+ differently from `async/1`, returns `{:ok, pid}` (which is
53
+ the result expected by supervision trees).
66
54
67
55
## Supervision trees
68
56
@@ -78,7 +66,7 @@ defmodule Task do
78
66
# In the remote node
79
67
Task.Supervisor.start_link(name: :tasks_sup)
80
68
81
- # On the client
69
+ # In the client
82
70
Task.Supervisor.async({:tasks_sup, :remote@local}, fn -> do_work() end)
83
71
84
72
`Task.Supervisor` is more often started in your supervision tree as:
@@ -118,7 +106,7 @@ defmodule Task do
118
106
"""
119
107
@ spec start_link ( module , atom , [ term ] ) :: { :ok , pid }
120
108
def start_link ( mod , fun , args ) do
121
- Task.Supervised . start_link ( :undefined , { mod , fun , args } )
109
+ Task.Supervised . start_link ( { mod , fun , args } )
122
110
end
123
111
124
112
@ doc """
0 commit comments