@@ -1339,9 +1339,9 @@ defmodule GenStage do
1339
1339
Sets the demand mode for a producer.
1340
1340
1341
1341
When `:forward`, the demand is always forwarded to the `c:handle_demand/2`
1342
- callback. When `:accumulate`, demand is accumulated until its mode is
1343
- set to `:forward`. This is useful as a synchronization mechanism, where
1344
- the demand is accumulated until all consumers are subscribed. Defaults
1342
+ callback. When `:accumulate`, both demand and events are accumulated until
1343
+ its mode is set to `:forward`. This is useful as a synchronization mechanism,
1344
+ where the demand is accumulated until all consumers are subscribed. Defaults
1345
1345
to `:forward`.
1346
1346
1347
1347
This command is asynchronous.
@@ -2261,11 +2261,11 @@ defmodule GenStage do
2261
2261
2262
2262
if is_list ( events ) do
2263
2263
fold_fun = fn
2264
- d , { :noreply , % { state: state } = stage } ->
2265
- noreply_callback ( :handle_demand , [ d , state ] , stage )
2264
+ event , { :noreply , stage } ->
2265
+ handle_accumulated_event ( event , stage )
2266
2266
2267
- d , { :noreply , % { state: state } = stage , _ } ->
2268
- noreply_callback ( :handle_demand , [ d , state ] , stage )
2267
+ event , { :noreply , stage , _ } ->
2268
+ handle_accumulated_event ( event , stage )
2269
2269
2270
2270
_ , { :stop , _ , _ } = acc ->
2271
2271
acc
@@ -2285,6 +2285,14 @@ defmodule GenStage do
2285
2285
end
2286
2286
end
2287
2287
2288
+ defp handle_accumulated_event ( { :demand , d } , stage ) do
2289
+ take_from_buffer_or_handle_demand ( d , stage )
2290
+ end
2291
+
2292
+ defp handle_accumulated_event ( { :dispatch , events , length } , stage ) do
2293
+ { :noreply , dispatch_events ( events , length , stage ) }
2294
+ end
2295
+
2288
2296
defp producer_subscribe ( opts , from , stage ) do
2289
2297
% { mod: mod , state: state , dispatcher_mod: dispatcher_mod , dispatcher_state: dispatcher_state } =
2290
2298
stage
@@ -2370,23 +2378,33 @@ defmodule GenStage do
2370
2378
take_pc_events ( queue , counter , stage )
2371
2379
2372
2380
% { } ->
2373
- case take_from_buffer ( counter , % { stage | dispatcher_state: dispatcher_state } ) do
2374
- { :ok , 0 , stage } ->
2375
- { :noreply , stage }
2381
+ take_from_buffer_or_handle_demand ( counter , % { stage | dispatcher_state: dispatcher_state } )
2382
+ end
2383
+ end
2376
2384
2377
- { :ok , counter , % { events: :forward , state: state } = stage } ->
2378
- noreply_callback ( :handle_demand , [ counter , state ] , stage )
2385
+ defp take_from_buffer_or_handle_demand ( counter , stage ) do
2386
+ case take_from_buffer ( counter , stage ) do
2387
+ { :ok , 0 , stage } ->
2388
+ { :noreply , stage }
2379
2389
2380
- { :ok , counter , % { events: events } = stage } when is_list ( events ) ->
2381
- { :noreply , % { stage | events: [ counter | events ] } }
2382
- end
2390
+ { :ok , counter , % { events: :forward , state: state } = stage } ->
2391
+ noreply_callback ( :handle_demand , [ counter , state ] , stage )
2392
+
2393
+ { :ok , counter , % { events: events } = stage } when is_list ( events ) ->
2394
+ { :noreply , % { stage | events: [ { :demand , counter } | events ] } }
2383
2395
end
2384
2396
end
2385
2397
2386
2398
defp dispatch_events ( [ ] , _length , stage ) do
2387
2399
stage
2388
2400
end
2389
2401
2402
+ # We don't dispatch when we are accumulating demand
2403
+ defp dispatch_events ( to_dispatch , length , % { events: events , type: :producer } = stage )
2404
+ when is_list ( events ) do
2405
+ % { stage | events: [ { :dispatch , to_dispatch , length } | events ] }
2406
+ end
2407
+
2390
2408
defp dispatch_events ( events , _length , % { type: :consumer } = stage ) do
2391
2409
error_msg =
2392
2410
~c" GenStage consumer ~tp cannot dispatch events (an empty list must be returned): ~tp~n"
0 commit comments