@@ -885,11 +885,18 @@ defmodule GenStage do
885
885
886
886
@ callback init ( args :: term ) ::
887
887
{ :producer , state }
888
+ | { :producer , state , { :continue , term } | :hibernate }
888
889
| { :producer , state , [ producer_option ] }
890
+ | { :producer , state , { :continue , term } | :hibernate , [ producer_option ] }
889
891
| { :producer_consumer , state }
892
+ | { :producer_consumer , state , { :continue , term } | :hibernate }
890
893
| { :producer_consumer , state , [ producer_consumer_option ] }
894
+ | { :producer_consumer , state , { :continue , term } | :hibernate ,
895
+ [ producer_consumer_option ] }
891
896
| { :consumer , state }
897
+ | { :consumer , state , { :continue , term } | :hibernate }
892
898
| { :consumer , state , [ consumer_option ] }
899
+ | { :consumer , state , { :continue , term } | :hibernate , [ consumer_option ] }
893
900
| :ignore
894
901
| { :stop , reason :: any }
895
902
when state: any
@@ -925,6 +932,7 @@ defmodule GenStage do
925
932
@ callback handle_demand ( demand :: pos_integer , state :: term ) ::
926
933
{ :noreply , [ event ] , new_state }
927
934
| { :noreply , [ event ] , new_state , :hibernate }
935
+ | { :noreply , [ event ] , new_state , { :continue , term } }
928
936
| { :stop , reason , new_state }
929
937
when new_state: term , reason: term , event: term
930
938
@@ -1004,6 +1012,7 @@ defmodule GenStage do
1004
1012
) ::
1005
1013
{ :noreply , [ event ] , new_state }
1006
1014
| { :noreply , [ event ] , new_state , :hibernate }
1015
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1007
1016
| { :stop , reason , new_state }
1008
1017
when event: term , new_state: term , reason: term
1009
1018
@@ -1017,6 +1026,7 @@ defmodule GenStage do
1017
1026
@ callback handle_events ( events :: [ event ] , from , state :: term ) ::
1018
1027
{ :noreply , [ event ] , new_state }
1019
1028
| { :noreply , [ event ] , new_state , :hibernate }
1029
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1020
1030
| { :stop , reason , new_state }
1021
1031
when new_state: term , reason: term , event: term
1022
1032
@@ -1056,8 +1066,10 @@ defmodule GenStage do
1056
1066
@ callback handle_call ( request :: term , from :: GenServer . from ( ) , state :: term ) ::
1057
1067
{ :reply , reply , [ event ] , new_state }
1058
1068
| { :reply , reply , [ event ] , new_state , :hibernate }
1069
+ | { :reply , reply , [ event ] , new_state , { :continue , term } }
1059
1070
| { :noreply , [ event ] , new_state }
1060
1071
| { :noreply , [ event ] , new_state , :hibernate }
1072
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1061
1073
| { :stop , reason , reply , new_state }
1062
1074
| { :stop , reason , new_state }
1063
1075
when reply: term , new_state: term , reason: term , event: term
@@ -1086,6 +1098,7 @@ defmodule GenStage do
1086
1098
@ callback handle_cast ( request :: term , state :: term ) ::
1087
1099
{ :noreply , [ event ] , new_state }
1088
1100
| { :noreply , [ event ] , new_state , :hibernate }
1101
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1089
1102
| { :stop , reason :: term , new_state }
1090
1103
when new_state: term , event: term
1091
1104
@@ -1103,6 +1116,27 @@ defmodule GenStage do
1103
1116
@ callback handle_info ( message :: term , state :: term ) ::
1104
1117
{ :noreply , [ event ] , new_state }
1105
1118
| { :noreply , [ event ] , new_state , :hibernate }
1119
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1120
+ | { :stop , reason :: term , new_state }
1121
+ when new_state: term , event: term
1122
+
1123
+ @ doc """
1124
+ Invoked to handle `continue` instructions.
1125
+
1126
+ It is useful for performing work after initialization or for splitting the work
1127
+ in a callback in multiple steps, updating the process state along the way.
1128
+
1129
+ Return values are the same as `c:handle_cast/2`.
1130
+
1131
+ This callback is optional. If one is not implemented, the server will fail
1132
+ if a continue instruction is used.
1133
+
1134
+ This callback is only supported on Erlang/OTP 21+.
1135
+ """
1136
+ @ callback handle_continue ( continue :: term , state :: term ) ::
1137
+ { :noreply , [ event ] , new_state }
1138
+ | { :noreply , [ event ] , new_state , :hibernate }
1139
+ | { :noreply , [ event ] , new_state , { :continue , term } }
1106
1140
| { :stop , reason :: term , new_state }
1107
1141
when new_state: term , event: term
1108
1142
@@ -1139,6 +1173,7 @@ defmodule GenStage do
1139
1173
format_status: 2 ,
1140
1174
handle_call: 3 ,
1141
1175
handle_cast: 2 ,
1176
+ handle_continue: 2 ,
1142
1177
handle_info: 2 ,
1143
1178
terminate: 2
1144
1179
]
@@ -1722,22 +1757,58 @@ defmodule GenStage do
1722
1757
def init ( { mod , args } ) do
1723
1758
case mod . init ( args ) do
1724
1759
{ :producer , state } ->
1725
- init_producer ( mod , [ ] , state )
1760
+ init_producer ( mod , [ ] , state , nil )
1761
+
1762
+ { :producer , state , { :continue , _term } = continue } ->
1763
+ init_producer ( mod , [ ] , state , continue )
1764
+
1765
+ { :producer , state , :hibernate } ->
1766
+ init_producer ( mod , [ ] , state , :hibernate )
1726
1767
1727
1768
{ :producer , state , opts } when is_list ( opts ) ->
1728
- init_producer ( mod , opts , state )
1769
+ init_producer ( mod , opts , state , nil )
1770
+
1771
+ { :producer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1772
+ init_producer ( mod , opts , state , continue )
1773
+
1774
+ { :producer , state , :hibernate , opts } when is_list ( opts ) ->
1775
+ init_producer ( mod , opts , state , :hibernate )
1729
1776
1730
1777
{ :producer_consumer , state } ->
1731
- init_producer_consumer ( mod , [ ] , state )
1778
+ init_producer_consumer ( mod , [ ] , state , nil )
1779
+
1780
+ { :producer_consumer , state , { :continue , _term } = continue } ->
1781
+ init_producer_consumer ( mod , [ ] , state , continue )
1782
+
1783
+ { :producer_consumer , state , :hibernate } ->
1784
+ init_producer_consumer ( mod , [ ] , state , :hibernate )
1732
1785
1733
1786
{ :producer_consumer , state , opts } when is_list ( opts ) ->
1734
- init_producer_consumer ( mod , opts , state )
1787
+ init_producer_consumer ( mod , opts , state , nil )
1788
+
1789
+ { :producer_consumer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1790
+ init_producer_consumer ( mod , opts , state , continue )
1791
+
1792
+ { :producer_consumer , state , :hibernate , opts } when is_list ( opts ) ->
1793
+ init_producer_consumer ( mod , opts , state , :hibernate )
1735
1794
1736
1795
{ :consumer , state } ->
1737
- init_consumer ( mod , [ ] , state )
1796
+ init_consumer ( mod , [ ] , state , nil )
1797
+
1798
+ { :consumer , state , { :continue , _term } = continue } ->
1799
+ init_consumer ( mod , [ ] , state , continue )
1800
+
1801
+ { :consumer , state , :hibernate } ->
1802
+ init_consumer ( mod , [ ] , state , :hibernate )
1738
1803
1739
1804
{ :consumer , state , opts } when is_list ( opts ) ->
1740
- init_consumer ( mod , opts , state )
1805
+ init_consumer ( mod , opts , state , nil )
1806
+
1807
+ { :consumer , state , { :continue , _term } = continue , opts } when is_list ( opts ) ->
1808
+ init_consumer ( mod , opts , state , continue )
1809
+
1810
+ { :consumer , state , :hibernate , opts } when is_list ( opts ) ->
1811
+ init_consumer ( mod , opts , state , :hibernate )
1741
1812
1742
1813
{ :stop , _ } = stop ->
1743
1814
stop
@@ -1750,7 +1821,7 @@ defmodule GenStage do
1750
1821
end
1751
1822
end
1752
1823
1753
- defp init_producer ( mod , opts , state ) do
1824
+ defp init_producer ( mod , opts , state , continue_or_hibernate ) do
1754
1825
with { :ok , dispatcher_mod , dispatcher_state , opts } <- init_dispatcher ( opts ) ,
1755
1826
{ :ok , buffer_size , opts } <-
1756
1827
Utils . validate_integer ( opts , :buffer_size , 10000 , 0 , :infinity , true ) ,
@@ -1770,7 +1841,7 @@ defmodule GenStage do
1770
1841
dispatcher_state: dispatcher_state
1771
1842
}
1772
1843
1773
- { :ok , stage }
1844
+ if continue_or_hibernate , do: { :ok , stage , continue_or_hibernate } , else: { :ok , stage }
1774
1845
else
1775
1846
{ :error , message } -> { :stop , { :bad_opts , message } }
1776
1847
end
@@ -1792,7 +1863,7 @@ defmodule GenStage do
1792
1863
end
1793
1864
end
1794
1865
1795
- defp init_producer_consumer ( mod , opts , state ) do
1866
+ defp init_producer_consumer ( mod , opts , state , continue_or_hibernate ) do
1796
1867
with { :ok , dispatcher_mod , dispatcher_state , opts } <- init_dispatcher ( opts ) ,
1797
1868
{ :ok , subscribe_to , opts } <- Utils . validate_list ( opts , :subscribe_to , [ ] ) ,
1798
1869
{ :ok , buffer_size , opts } <-
@@ -1811,22 +1882,68 @@ defmodule GenStage do
1811
1882
dispatcher_state: dispatcher_state
1812
1883
}
1813
1884
1814
- consumer_init_subscribe ( subscribe_to , stage )
1885
+ case handle_gen_server_init_args ( continue_or_hibernate , stage ) do
1886
+ { :ok , stage } ->
1887
+ consumer_init_subscribe ( subscribe_to , stage )
1888
+
1889
+ { :ok , stage , args } ->
1890
+ { :ok , stage } = consumer_init_subscribe ( subscribe_to , stage )
1891
+ { :ok , stage , args }
1892
+
1893
+ { :stop , _ , _ } = error ->
1894
+ error
1895
+ end
1815
1896
else
1816
1897
{ :error , message } -> { :stop , { :bad_opts , message } }
1817
1898
end
1818
1899
end
1819
1900
1820
- defp init_consumer ( mod , opts , state ) do
1901
+ defp init_consumer ( mod , opts , state , continue_or_hibernate ) do
1821
1902
with { :ok , subscribe_to , opts } <- Utils . validate_list ( opts , :subscribe_to , [ ] ) ,
1822
1903
:ok <- Utils . validate_no_opts ( opts ) do
1823
1904
stage = % GenStage { mod: mod , state: state , type: :consumer }
1824
- consumer_init_subscribe ( subscribe_to , stage )
1905
+
1906
+ case handle_gen_server_init_args ( continue_or_hibernate , stage ) do
1907
+ { :ok , stage } ->
1908
+ consumer_init_subscribe ( subscribe_to , stage )
1909
+
1910
+ { :ok , stage , args } ->
1911
+ { :ok , stage } = consumer_init_subscribe ( subscribe_to , stage )
1912
+ { :ok , stage , args }
1913
+
1914
+ { :stop , _ , _ } = error ->
1915
+ error
1916
+ end
1825
1917
else
1826
1918
{ :error , message } -> { :stop , { :bad_opts , message } }
1827
1919
end
1828
1920
end
1829
1921
1922
+ defp handle_gen_server_init_args ( { :continue , _term } = continue , stage ) do
1923
+ case handle_continue ( continue , stage ) do
1924
+ { :noreply , stage } ->
1925
+ { :ok , stage }
1926
+
1927
+ { :noreply , stage , :hibernate } ->
1928
+ { :ok , stage , :hibernate }
1929
+
1930
+ { :noreply , stage , { :continue , _term } = continue } ->
1931
+ { :ok , stage , continue }
1932
+
1933
+ { :stop , reason , stage } ->
1934
+ { :stop , reason , stage }
1935
+ end
1936
+ end
1937
+
1938
+ defp handle_gen_server_init_args ( :hibernate , stage ) , do: { :ok , stage , :hibernate }
1939
+ defp handle_gen_server_init_args ( nil , stage ) , do: { :ok , stage }
1940
+
1941
+ @ doc false
1942
+
1943
+ def handle_continue ( continue , % { state: state } = stage ) do
1944
+ noreply_callback ( :handle_continue , [ continue , state ] , stage )
1945
+ end
1946
+
1830
1947
@ doc false
1831
1948
1832
1949
def handle_call ( { :"$info" , msg } , _from , stage ) do
@@ -1855,6 +1972,10 @@ defmodule GenStage do
1855
1972
stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
1856
1973
{ :reply , reply , stage , :hibernate }
1857
1974
1975
+ { :reply , reply , events , state , { :continue , _term } = continue } ->
1976
+ stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
1977
+ { :reply , reply , stage , continue }
1978
+
1858
1979
{ :stop , reason , reply , state } ->
1859
1980
{ :stop , reason , reply , % { stage | state: state } }
1860
1981
@@ -1995,7 +2116,7 @@ defmodule GenStage do
1995
2116
case producers do
1996
2117
% { ^ ref => entry } ->
1997
2118
{ batches , stage } = consumer_receive ( from , entry , events , stage )
1998
- consumer_dispatch ( batches , from , mod , state , stage , false )
2119
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
1999
2120
2000
2121
_ ->
2001
2122
msg = { :"$gen_producer" , { self ( ) , ref } , { :cancel , :unknown_subscription } }
@@ -2122,6 +2243,14 @@ defmodule GenStage do
2122
2243
end
2123
2244
end
2124
2245
2246
+ defp noreply_callback ( :handle_continue , [ continue , state ] , % { mod: mod } = stage ) do
2247
+ if function_exported? ( mod , :handle_continue , 2 ) do
2248
+ handle_noreply_callback ( mod . handle_continue ( continue , state ) , stage )
2249
+ else
2250
+ :error_handler . raise_undef_exception ( mod , :handle_continue , [ continue , state ] )
2251
+ end
2252
+ end
2253
+
2125
2254
defp noreply_callback ( callback , args , % { mod: mod } = stage ) do
2126
2255
handle_noreply_callback ( apply ( mod , callback , args ) , stage )
2127
2256
end
@@ -2136,6 +2265,10 @@ defmodule GenStage do
2136
2265
stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
2137
2266
{ :noreply , stage , :hibernate }
2138
2267
2268
+ { :noreply , events , state , { :continue , _term } = continue } when is_list ( events ) ->
2269
+ stage = dispatch_events ( events , length ( events ) , % { stage | state: state } )
2270
+ { :noreply , stage , continue }
2271
+
2139
2272
{ :stop , reason , state } ->
2140
2273
{ :stop , reason , % { stage | state: state } }
2141
2274
@@ -2259,6 +2392,9 @@ defmodule GenStage do
2259
2392
# main module must know the consumer is no longer subscribed.
2260
2393
dispatcher_callback ( :cancel , [ { pid , ref } , dispatcher_state ] , stage )
2261
2394
2395
+ { :noreply , % { dispatcher_state: dispatcher_state } = stage , _hibernate_or_continue } ->
2396
+ dispatcher_callback ( :cancel , [ { pid , ref } , dispatcher_state ] , stage )
2397
+
2262
2398
{ :stop , _ , _ } = stop ->
2263
2399
stop
2264
2400
end
@@ -2459,17 +2595,22 @@ defmodule GenStage do
2459
2595
{ [ { events , 0 } ] , stage }
2460
2596
end
2461
2597
2462
- defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , _hibernate? ) do
2598
+ defp consumer_dispatch ( [ { batch , ask } | batches ] , from , mod , state , stage , _gen_opts ) do
2463
2599
case mod . handle_events ( batch , from , state ) do
2464
2600
{ :noreply , events , state } when is_list ( events ) ->
2465
2601
stage = dispatch_events ( events , length ( events ) , stage )
2466
2602
ask ( from , ask , [ :noconnect ] )
2467
- consumer_dispatch ( batches , from , mod , state , stage , false )
2603
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
2468
2604
2469
- { :noreply , events , state , :hibernate } when is_list ( events ) ->
2605
+ { :noreply , events , state , :hibernate } ->
2470
2606
stage = dispatch_events ( events , length ( events ) , stage )
2471
2607
ask ( from , ask , [ :noconnect ] )
2472
- consumer_dispatch ( batches , from , mod , state , stage , true )
2608
+ consumer_dispatch ( batches , from , mod , state , stage , :hibernate )
2609
+
2610
+ { :noreply , events , state , { :continue , _ } = continue } ->
2611
+ stage = dispatch_events ( events , length ( events ) , stage )
2612
+ ask ( from , ask , [ :noconnect ] )
2613
+ consumer_dispatch ( batches , from , mod , state , stage , continue )
2473
2614
2474
2615
{ :stop , reason , state } ->
2475
2616
{ :stop , reason , % { stage | state: state } }
@@ -2479,12 +2620,12 @@ defmodule GenStage do
2479
2620
end
2480
2621
end
2481
2622
2482
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , false ) do
2623
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , nil ) do
2483
2624
{ :noreply , % { stage | state: state } }
2484
2625
end
2485
2626
2486
- defp consumer_dispatch ( [ ] , _from , _mod , state , stage , true ) do
2487
- { :noreply , % { stage | state: state } , :hibernate }
2627
+ defp consumer_dispatch ( [ ] , _from , _mod , state , stage , gen_opts ) do
2628
+ { :noreply , % { stage | state: state } , gen_opts }
2488
2629
end
2489
2630
2490
2631
defp consumer_subscribe ( { to , opts } , stage ) when is_list ( opts ) ,
@@ -2613,11 +2754,11 @@ defmodule GenStage do
2613
2754
{ producer_id , _ , _ } = entry
2614
2755
from = { producer_id , ref }
2615
2756
{ batches , stage } = consumer_receive ( from , entry , events , stage )
2616
- consumer_dispatch ( batches , from , mod , state , stage , false )
2757
+ consumer_dispatch ( batches , from , mod , state , stage , nil )
2617
2758
2618
2759
% { } ->
2619
2760
# We queued but producer was removed
2620
- consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , false )
2761
+ consumer_dispatch ( [ { events , 0 } ] , { :pid , ref } , mod , state , stage , nil )
2621
2762
end
2622
2763
end
2623
2764
@@ -2634,6 +2775,9 @@ defmodule GenStage do
2634
2775
{ :noreply , stage , :hibernate } ->
2635
2776
take_pc_events ( queue , counter , stage )
2636
2777
2778
+ { :noreply , stage , { :continue , _term } } ->
2779
+ take_pc_events ( queue , counter , stage )
2780
+
2637
2781
{ :stop , _ , _ } = stop ->
2638
2782
stop
2639
2783
end
@@ -2646,6 +2790,9 @@ defmodule GenStage do
2646
2790
{ :noreply , % { events: { queue , counter } } = stage , :hibernate } ->
2647
2791
take_pc_events ( queue , counter , stage )
2648
2792
2793
+ { :noreply , % { events: { queue , counter } } = stage , { :continue , _term } } ->
2794
+ take_pc_events ( queue , counter , stage )
2795
+
2649
2796
{ :stop , _ , _ } = stop ->
2650
2797
stop
2651
2798
end
0 commit comments