@@ -909,11 +909,18 @@ defmodule GenStage do
909
909
910
910
@ callback init ( args :: term ) ::
911
911
{ :producer , state }
912
+ | { :producer , state , { :continue , term } | :hibernate }
912
913
| { :producer , state , [ producer_option ] }
914
+ | { :producer , state , { :continue , term } | :hibernate , [ producer_option ] }
913
915
| { :producer_consumer , state }
916
+ | { :producer_consumer , state , { :continue , term } | :hibernate }
914
917
| { :producer_consumer , state , [ producer_consumer_option ] }
918
+ | { :producer_consumer , state , { :continue , term } | :hibernate ,
919
+ [ producer_consumer_option ] }
915
920
| { :consumer , state }
921
+ | { :consumer , state , { :continue , term } | :hibernate }
916
922
| { :consumer , state , [ consumer_option ] }
923
+ | { :consumer , state , { :continue , term } | :hibernate , [ consumer_option ] }
917
924
| :ignore
918
925
| { :stop , reason :: any }
919
926
when state: any
@@ -996,6 +1003,7 @@ defmodule GenStage do
996
1003
@ callback handle_demand ( demand :: pos_integer , state :: term ) ::
997
1004
{ :noreply , [ event ] , new_state }
998
1005
| { :noreply , [ event ] , new_state , :hibernate }
1006
+ | { :noreply , [ event ] , new_state , { :continue , term } }
999
1007
| { :stop , reason , new_state }
1000
1008
when new_state: term , reason: term , event: term
1001
1009
@@ -1075,6 +1083,7 @@ defmodule GenStage do
1075
1083
) ::
1076
1084
{ :noreply , [ event ] , new_state }
1077
1085
| { :noreply , [ event ] , new_state , :hibernate }
1086
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1078
1087
| { :stop , reason , new_state }
1079
1088
when event: term , new_state: term , reason: term
1080
1089
@@ -1088,6 +1097,7 @@ defmodule GenStage do
1088
1097
@ callback handle_events ( events :: [ event ] , from , state :: term ) ::
1089
1098
{ :noreply , [ event ] , new_state }
1090
1099
| { :noreply , [ event ] , new_state , :hibernate }
1100
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1091
1101
| { :stop , reason , new_state }
1092
1102
when new_state: term , reason: term , event: term
1093
1103
@@ -1129,8 +1139,10 @@ defmodule GenStage do
1129
1139
@ callback handle_call ( request :: term , from :: GenServer . from ( ) , state :: term ) ::
1130
1140
{ :reply , reply , [ event ] , new_state }
1131
1141
| { :reply , reply , [ event ] , new_state , :hibernate }
1142
+ | { :reply , reply , [ event ] , new_state , { :continue , term } }
1132
1143
| { :noreply , [ event ] , new_state }
1133
1144
| { :noreply , [ event ] , new_state , :hibernate }
1145
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1134
1146
| { :stop , reason , reply , new_state }
1135
1147
| { :stop , reason , new_state }
1136
1148
when reply: term , new_state: term , reason: term , event: term
@@ -1161,6 +1173,7 @@ defmodule GenStage do
1161
1173
@ callback handle_cast ( request :: term , state :: term ) ::
1162
1174
{ :noreply , [ event ] , new_state }
1163
1175
| { :noreply , [ event ] , new_state , :hibernate }
1176
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1164
1177
| { :stop , reason :: term , new_state }
1165
1178
when new_state: term , event: term
1166
1179
@@ -1181,6 +1194,27 @@ defmodule GenStage do
1181
1194
@ callback handle_info ( message :: term , state :: term ) ::
1182
1195
{ :noreply , [ event ] , new_state }
1183
1196
| { :noreply , [ event ] , new_state , :hibernate }
1197
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1198
+ | { :stop , reason :: term , new_state }
1199
+ when new_state: term , event: term
1200
+
1201
+ @ doc """
1202
+ Invoked to handle `continue` instructions.
1203
+
1204
+ It is useful for performing work after initialization or for splitting the work
1205
+ in a callback in multiple steps, updating the process state along the way.
1206
+
1207
+ Return values are the same as `c:handle_cast/2`.
1208
+
1209
+ This callback is optional. If one is not implemented, the server will fail
1210
+ if a continue instruction is used.
1211
+
1212
+ This callback is only supported on Erlang/OTP 21+.
1213
+ """
1214
+ @ callback handle_continue ( continue :: term , state :: term ) ::
1215
+ { :noreply , [ event ] , new_state }
1216
+ | { :noreply , [ event ] , new_state , :hibernate }
1217
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1184
1218
| { :stop , reason :: term , new_state }
1185
1219
when new_state: term , event: term
1186
1220
@@ -1217,6 +1251,7 @@ defmodule GenStage do
1217
1251
format_status: 2 ,
1218
1252
handle_call: 3 ,
1219
1253
handle_cast: 2 ,
1254
+ handle_continue: 2 ,
1220
1255
handle_info: 2 ,
1221
1256
terminate: 2
1222
1257
]
@@ -1815,22 +1850,58 @@ defmodule GenStage do
1815
1850
def init ( { mod , args } ) do
1816
1851
case mod . init ( args ) do
1817
1852
{ :producer , state } ->
1818
- init_producer ( mod , [ ] , state )
1853
+ init_producer ( mod , [ ] , state , nil )
1854
+
1855
+ { :producer , state , { :continue , _term } = continue } ->
1856
+ init_producer ( mod , [ ] , state , continue )
1857
+
1858
+ { :producer , state , :hibernate } ->
1859
+ init_producer ( mod , [ ] , state , :hibernate )
1819
1860
1820
1861
{ :producer , state , opts } when is_list ( opts ) ->
1821
- init_producer ( mod , opts , state )
1862
+ init_producer ( mod , opts , state , nil )
1863
+
1864
+ { :producer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1865
+ init_producer ( mod , opts , state , continue )
1866
+
1867
+ { :producer , state , :hibernate , opts } when is_list ( opts ) ->
1868
+ init_producer ( mod , opts , state , :hibernate )
1822
1869
1823
1870
{ :producer_consumer , state } ->
1824
- init_producer_consumer ( mod , [ ] , state )
1871
+ init_producer_consumer ( mod , [ ] , state , nil )
1872
+
1873
+ { :producer_consumer , state , { :continue , _term } = continue } ->
1874
+ init_producer_consumer ( mod , [ ] , state , continue )
1875
+
1876
+ { :producer_consumer , state , :hibernate } ->
1877
+ init_producer_consumer ( mod , [ ] , state , :hibernate )
1825
1878
1826
1879
{ :producer_consumer , state , opts } when is_list ( opts ) ->
1827
- init_producer_consumer ( mod , opts , state )
1880
+ init_producer_consumer ( mod , opts , state , nil )
1881
+
1882
+ { :producer_consumer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1883
+ init_producer_consumer ( mod , opts , state , continue )
1884
+
1885
+ { :producer_consumer , state , :hibernate , opts } when is_list ( opts ) ->
1886
+ init_producer_consumer ( mod , opts , state , :hibernate )
1828
1887
1829
1888
{ :consumer , state } ->
1830
- init_consumer ( mod , [ ] , state )
1889
+ init_consumer ( mod , [ ] , state , nil )
1890
+
1891
+ { :consumer , state , { :continue , _term } = continue } ->
1892
+ init_consumer ( mod , [ ] , state , continue )
1893
+
1894
+ { :consumer , state , :hibernate } ->
1895
+ init_consumer ( mod , [ ] , state , :hibernate )
1831
1896
1832
1897
{ :consumer , state , opts } when is_list ( opts ) ->
1833
- init_consumer ( mod , opts , state )
1898
+ init_consumer ( mod , opts , state , nil )
1899
+
1900
+ { :consumer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1901
+ init_consumer ( mod , opts , state , continue )
1902
+
1903
+ { :consumer , state , :hibernate , opts } when is_list ( opts ) ->
1904
+ init_consumer ( mod , opts , state , :hibernate )
1834
1905
1835
1906
{ :stop , _ } = stop ->
1836
1907
stop
@@ -1843,7 +1914,7 @@ defmodule GenStage do
1843
1914
end
1844
1915
end
1845
1916
1846
- defp init_producer ( mod , opts , state ) do
1917
+ defp init_producer ( mod , opts , state , continue_or_hibernate ) do
1847
1918
with { :ok , dispatcher_mod , dispatcher_state , opts } <- init_dispatcher ( opts ) ,
1848
1919
{ :ok , buffer_size , opts } <-
1849
1920
Utils . validate_integer ( opts , :buffer_size , 10000 , 0 , :infinity , true ) ,
@@ -1863,7 +1934,7 @@ defmodule GenStage do
1863
1934
dispatcher_state: dispatcher_state
1864
1935
}
1865
1936
1866
- { :ok , stage }
1937
+ if continue_or_hibernate , do: { :ok , stage , continue_or_hibernate } , else: { :ok , stage }
1867
1938
else
1868
1939
{ :error , message } -> { :stop , { :bad_opts , message } }
1869
1940
end
@@ -1885,7 +1956,7 @@ defmodule GenStage do
1885
1956
end
1886
1957
end
1887
1958
1888
- defp init_producer_consumer ( mod , opts , state ) do
1959
+ defp init_producer_consumer ( mod , opts , state , continue_or_hibernate ) do
1889
1960
with { :ok , dispatcher_mod , dispatcher_state , opts } <- init_dispatcher ( opts ) ,
1890
1961
{ :ok , subscribe_to , opts } <- Utils . validate_list ( opts , :subscribe_to , [ ] ) ,
1891
1962
{ :ok , buffer_size , opts } <-
@@ -1904,22 +1975,68 @@ defmodule GenStage do
1904
1975
dispatcher_state: dispatcher_state
1905
1976
}
1906
1977
1907
- consumer_init_subscribe ( subscribe_to , stage )
1978
+ case handle_gen_server_init_args ( continue_or_hibernate , stage ) do
1979
+ { :ok , stage } ->
1980
+ consumer_init_subscribe ( subscribe_to , stage )
1981
+
1982
+ { :ok , stage , args } ->
1983
+ { :ok , stage } = consumer_init_subscribe ( subscribe_to , stage )
1984
+ { :ok , stage , args }
1985
+
1986
+ { :stop , _ , _ } = error ->
1987
+ error
1988
+ end
1908
1989
else
1909
1990
{ :error , message } -> { :stop , { :bad_opts , message } }
1910
1991
end
1911
1992
end
1912
1993
1913
- defp init_consumer ( mod , opts , state ) do
1994
+ defp init_consumer ( mod , opts , state , continue_or_hibernate ) do
1914
1995
with { :ok , subscribe_to , opts } <- Utils . validate_list ( opts , :subscribe_to , [ ] ) ,
1915
1996
:ok <- Utils . validate_no_opts ( opts ) do
1916
1997
stage = % GenStage { mod: mod , state: state , type: :consumer }
1917
- consumer_init_subscribe ( subscribe_to , stage )
1998
+
1999
+ case handle_gen_server_init_args ( continue_or_hibernate , stage ) do
2000
+ { :ok , stage } ->
2001
+ consumer_init_subscribe ( subscribe_to , stage )
2002
+
2003
+ { :ok , stage , args } ->
2004
+ { :ok , stage } = consumer_init_subscribe ( subscribe_to , stage )
2005
+ { :ok , stage , args }
2006
+
2007
+ { :stop , _ , _ } = error ->
2008
+ error
2009
+ end
1918
2010
else
1919
2011
{ :error , message } -> { :stop , { :bad_opts , message } }
1920
2012
end
1921
2013
end
1922
2014
2015
+ defp handle_gen_server_init_args ( { :continue , _term } = continue , stage ) do
2016
+ case handle_continue ( continue , stage ) do
2017
+ { :noreply , stage } ->
2018
+ { :ok , stage }
2019
+
2020
+ { :noreply , stage , :hibernate } ->
2021
+ { :ok , stage , :hibernate }
2022
+
2023
+ { :noreply , stage , { :continue , _term } = continue } ->
2024
+ { :ok , stage , continue }
2025
+
2026
+ { :stop , reason , stage } ->
2027
+ { :stop , reason , stage }
2028
+ end
2029
+ end
2030
+
2031
+ defp handle_gen_server_init_args ( :hibernate , stage ) , do: { :ok , stage , :hibernate }
2032
+ defp handle_gen_server_init_args ( nil , stage ) , do: { :ok , stage }
2033
+
2034
+ @ doc false
2035
+
2036
+ def handle_continue ( continue , % { state: state } = stage ) do
2037
+ noreply_callback ( :handle_continue , [ continue , state ] , stage )
2038
+ end
2039
+
1923
2040
@ doc false
1924
2041
1925
2042
def handle_call ( { :"$info" , msg } , _from , stage ) do
@@ -1948,6 +2065,10 @@ defmodule GenStage do
1948
2065
stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
1949
2066
{ :reply , reply , stage , :hibernate }
1950
2067
2068
+ { :reply , reply , events , state , { :continue , _term } = continue } ->
2069
+ stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
2070
+ { :reply , reply , stage , continue }
2071
+
1951
2072
{ :stop , reason , reply , state } ->
1952
2073
{ :stop , reason , reply , % { stage | state: state } }
1953
2074
@@ -2092,7 +2213,7 @@ defmodule GenStage do
2092
2213
case producers do
2093
2214
% { ^ ref => entry } ->
2094
2215
{ batches , stage } = consumer_receive ( from , entry , events , stage )
2095
- consumer_dispatch ( batches , from , mod , state , stage , false )
2216
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
2096
2217
2097
2218
_ ->
2098
2219
msg = { :"$gen_producer" , { self ( ) , ref } , { :cancel , :unknown_subscription } }
@@ -2219,6 +2340,14 @@ defmodule GenStage do
2219
2340
end
2220
2341
end
2221
2342
2343
+ defp noreply_callback ( :handle_continue , [ continue , state ] , % { mod: mod } = stage ) do
2344
+ if function_exported? ( mod , :handle_continue , 2 ) do
2345
+ handle_noreply_callback ( mod . handle_continue ( continue , state ) , stage )
2346
+ else
2347
+ :error_handler . raise_undef_exception ( mod , :handle_continue , [ continue , state ] )
2348
+ end
2349
+ end
2350
+
2222
2351
defp noreply_callback ( callback , args , % { mod: mod } = stage ) do
2223
2352
handle_noreply_callback ( apply ( mod , callback , args ) , stage )
2224
2353
end
@@ -2233,6 +2362,10 @@ defmodule GenStage do
2233
2362
stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
2234
2363
{ :noreply , stage , :hibernate }
2235
2364
2365
+ { :noreply , events , state , { :continue , _term } = continue } when is_list ( events ) ->
2366
+ stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
2367
+ { :noreply , stage , continue }
2368
+
2236
2369
{ :stop , reason , state } ->
2237
2370
{ :stop , reason , % { stage | state: state } }
2238
2371
@@ -2364,6 +2497,9 @@ defmodule GenStage do
2364
2497
# main module must know the consumer is no longer subscribed.
2365
2498
dispatcher_callback ( :cancel , [ { pid , ref } , dispatcher_state ] , stage )
2366
2499
2500
+ { :noreply , % { dispatcher_state: dispatcher_state } = stage , _hibernate_or_continue } ->
2501
+ dispatcher_callback ( :cancel , [ { pid , ref } , dispatcher_state ] , stage )
2502
+
2367
2503
{ :stop , _ , _ } = stop ->
2368
2504
stop
2369
2505
end
@@ -2574,17 +2710,22 @@ defmodule GenStage do
2574
2710
{ [ { events , 0 } ] , stage }
2575
2711
end
2576
2712
2577
- defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , _hibernate? ) do
2713
+ defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , _gen_opts ) do
2578
2714
case mod . handle_events ( batch , from , state ) do
2579
2715
{ :noreply , events , state } when is_list ( events ) ->
2580
2716
stage = dispatch_events ( events , length ( events ) , stage )
2581
2717
ask ( from , ask , [ :noconnect ] )
2582
- consumer_dispatch ( batches , from , mod , state , stage , false )
2718
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
2583
2719
2584
- { :noreply , events , state , :hibernate } when is_list ( events ) ->
2720
+ { :noreply , events , state , :hibernate } ->
2585
2721
stage = dispatch_events ( events , length ( events ) , stage )
2586
2722
ask ( from , ask , [ :noconnect ] )
2587
- consumer_dispatch ( batches , from , mod , state , stage , true )
2723
+ consumer_dispatch ( batches , from , mod , state , stage , :hibernate )
2724
+
2725
+ { :noreply , events , state , { :continue , _ } = continue } ->
2726
+ stage = dispatch_events ( events , length ( events ) , stage )
2727
+ ask ( from , ask , [ :noconnect ] )
2728
+ consumer_dispatch ( batches , from , mod , state , stage , continue )
2588
2729
2589
2730
{ :stop , reason , state } ->
2590
2731
{ :stop , reason , % { stage | state: state } }
@@ -2594,12 +2735,12 @@ defmodule GenStage do
2594
2735
end
2595
2736
end
2596
2737
2597
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , false ) do
2738
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , nil ) do
2598
2739
{ :noreply , % { stage | state: state } }
2599
2740
end
2600
2741
2601
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , true ) do
2602
- { :noreply , % { stage | state: state } , :hibernate }
2742
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , gen_opts ) do
2743
+ { :noreply , % { stage | state: state } , gen_opts }
2603
2744
end
2604
2745
2605
2746
defp consumer_subscribe ( { to , opts } , stage ) when is_list ( opts ) ,
@@ -2738,11 +2879,11 @@ defmodule GenStage do
2738
2879
{ producer_id , _ , _ } = entry
2739
2880
from = { producer_id , ref }
2740
2881
{ batches , stage } = consumer_receive ( from , entry , events , stage )
2741
- consumer_dispatch ( batches , from , mod , state , stage , false )
2882
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
2742
2883
2743
2884
% { } ->
2744
2885
# We queued but producer was removed
2745
- consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , false )
2886
+ consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , nil )
2746
2887
end
2747
2888
end
2748
2889
@@ -2759,6 +2900,9 @@ defmodule GenStage do
2759
2900
{ :noreply , stage , :hibernate } ->
2760
2901
take_pc_events ( queue , counter , stage )
2761
2902
2903
+ { :noreply , stage , { :continue , _term } } ->
2904
+ take_pc_events ( queue , counter , stage )
2905
+
2762
2906
{ :stop , _ , _ } = stop ->
2763
2907
stop
2764
2908
end
@@ -2771,6 +2915,9 @@ defmodule GenStage do
2771
2915
{ :noreply , % { events: { queue , counter } } = stage , :hibernate } ->
2772
2916
take_pc_events ( queue , counter , stage )
2773
2917
2918
+ { :noreply , % { events: { queue , counter } } = stage , { :continue , _term } } ->
2919
+ take_pc_events ( queue , counter , stage )
2920
+
2774
2921
{ :stop , _ , _ } = stop ->
2775
2922
stop
2776
2923
end
0 commit comments