@@ -1109,7 +1109,8 @@ defmodule Task do
1109
1109
* `{:ok, term}` if the task has successfully reported its
1110
1110
result back in the given time interval
1111
1111
* `{:exit, reason}` if the task has died
1112
- * `nil` if the task keeps running past the timeout
1112
+ * `nil` if the task keeps running, either because a limit
1113
+ has been reached or past the timeout
1113
1114
1114
1115
Check `yield/2` for more information.
1115
1116
@@ -1162,6 +1163,10 @@ defmodule Task do
1162
1163
The second argument is either a timeout or options, which defaults
1163
1164
to this:
1164
1165
1166
+ * `:limit` - the maximum amount of tasks to wait for.
1167
+ If the limit is reached before the timeout, this function
1168
+ returns immediately without triggering the `:on_timeout` behaviour
1169
+
1165
1170
* `:timeout` - the maximum amount of time (in milliseconds or `:infinity`)
1166
1171
each task is allowed to execute for. Defaults to `5000`.
1167
1172
@@ -1173,7 +1178,11 @@ defmodule Task do
1173
1178
* `:kill_task` - the task that timed out is killed.
1174
1179
"""
1175
1180
@ spec yield_many ( [ t ] , timeout ) :: [ { t , { :ok , term } | { :exit , term } | nil } ]
1176
- @ spec yield_many ( [ t ] , timeout: timeout , on_timeout: :nothing | :ignore | :kill_task ) ::
1181
+ @ spec yield_many ( [ t ] ,
1182
+ limit: pos_integer ( ) ,
1183
+ timeout: timeout ,
1184
+ on_timeout: :nothing | :ignore | :kill_task
1185
+ ) ::
1177
1186
[ { t , { :ok , term } | { :exit , term } | nil } ]
1178
1187
def yield_many ( tasks , opts \\ [ ] )
1179
1188
@@ -1182,9 +1191,6 @@ defmodule Task do
1182
1191
end
1183
1192
1184
1193
def yield_many ( tasks , opts ) when is_list ( opts ) do
1185
- on_timeout = Keyword . get ( opts , :on_timeout , :nothing )
1186
- timeout = Keyword . get ( opts , :timeout , 5_000 )
1187
-
1188
1194
refs =
1189
1195
Map . new ( tasks , fn % Task { ref: ref , owner: owner } = task ->
1190
1196
if owner != self ( ) do
@@ -1194,6 +1200,9 @@ defmodule Task do
1194
1200
{ ref , nil }
1195
1201
end )
1196
1202
1203
+ on_timeout = Keyword . get ( opts , :on_timeout , :nothing )
1204
+ timeout = Keyword . get ( opts , :timeout , 5_000 )
1205
+ limit = Keyword . get ( opts , :limit , map_size ( refs ) )
1197
1206
timeout_ref = make_ref ( )
1198
1207
1199
1208
timer_ref =
@@ -1202,16 +1211,17 @@ defmodule Task do
1202
1211
end
1203
1212
1204
1213
try do
1205
- yield_many ( map_size ( refs ) , refs , timeout_ref , timer_ref )
1214
+ yield_many ( limit , refs , timeout_ref , timer_ref )
1206
1215
catch
1207
1216
{ :noconnection , reason } ->
1208
1217
exit ( { reason , { __MODULE__ , :yield_many , [ tasks , timeout ] } } )
1209
1218
else
1210
- refs ->
1219
+ { timed_out? , refs } ->
1211
1220
for task <- tasks do
1212
1221
value =
1213
1222
with nil <- Map . fetch! ( refs , task . ref ) do
1214
1223
case on_timeout do
1224
+ _ when not timed_out? -> nil
1215
1225
:nothing -> nil
1216
1226
:kill_task -> shutdown ( task , :brutal_kill )
1217
1227
:ignore -> ignore ( task )
@@ -1226,7 +1236,7 @@ defmodule Task do
1226
1236
defp yield_many ( 0 , refs , timeout_ref , timer_ref ) do
1227
1237
timer_ref && Process . cancel_timer ( timer_ref )
1228
1238
receive do: ( ^ timeout_ref -> :ok ) , after: ( 0 -> :ok )
1229
- refs
1239
+ { false , refs }
1230
1240
end
1231
1241
1232
1242
defp yield_many ( limit , refs , timeout_ref , timer_ref ) do
@@ -1243,7 +1253,7 @@ defmodule Task do
1243
1253
end
1244
1254
1245
1255
^ timeout_ref ->
1246
- refs
1256
+ { true , refs }
1247
1257
end
1248
1258
end
1249
1259
0 commit comments