Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add {continue, Term} and handle_continue/2 to gen_server #1490

Merged
merged 1 commit into from
Sep 6, 2017

Conversation

josevalim
Copy link
Contributor

@josevalim josevalim commented Jun 22, 2017

If the gen_server process needs to perform an action immediately
after initialization or to break the execution of a callback into
multiple steps, it can return {continue, term()} in place of the
time-out or hibernation value, which will immediately invoke the
handle_continue/2 callback with the given term.

This provides a more accessible approach to after initialization
compared to proc_lib+enter_loop that is also guaranteed to be
safe.

It also allows callbacks that need to do lengthy or stateful work
to checkpoint the state throughout multiple iterations. This can
be useful, for example, when implementing behaviours on top of
gen_server.

This is continuation of PR #1429.

handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod,
HibernateAfterTimeout, State);
_ ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, Msg),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RaimoNiskanen I have chosen the debug event to be {continue, Continue}. Is that ok? If there is an error, we will also log the last message as {continue, Continue}.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks just fine

@IngelaAndin IngelaAndin added team:PS Assigned to OTP team PS team:MW labels Jun 24, 2017
@IngelaAndin
Copy link
Contributor

We intend to make a decision about this PR before the next planned release but feedback loop might be a bit slower than usual during the summer so please have patience.

@IngelaAndin IngelaAndin added the testing currently being tested, tag is used by OTP internal CI label Jul 6, 2017
@IngelaAndin
Copy link
Contributor

The test case gen_server_incorrect_args in behaviour_SUITE in dialyzer fails with your branch:

{test_server,ts_tc,1529}
{test_case_failed,{differ,[{new,4, "gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer() | {'continue',_}} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer() | {'continue',_}} | {'stop',_,_,_}, which is the expected return type for the callback of the gen_server behaviour\n"}, {old,4, "gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of the gen_server behaviour\n"}]}}

@IngelaAndin IngelaAndin added waiting waiting for changes/input from author and removed testing currently being tested, tag is used by OTP internal CI labels Jul 7, 2017
@josevalim
Copy link
Contributor Author

josevalim commented Jul 7, 2017

@IngelaAndin fixed and force pushed, thanks!

@IngelaAndin IngelaAndin added testing currently being tested, tag is used by OTP internal CI feature and removed waiting waiting for changes/input from author labels Jul 7, 2017
@RaimoNiskanen
Copy link
Contributor

Sorry about the delay, but another test case fails and I did not see that until now. It is a white box test case in stdlib - erl_internal_SUITE:behav that probably needs {handle_continue, 2} appended to the return value of optional_callbacks(gen_server).

@RaimoNiskanen RaimoNiskanen added waiting waiting for changes/input from author and removed testing currently being tested, tag is used by OTP internal CI labels Jul 27, 2017
@josevalim
Copy link
Contributor Author

@RaimoNiskanen no worries! I will gladly look into it later today.

@josevalim
Copy link
Contributor Author

@RaimoNiskanen fixed and force pushed. I re-ran the stdlib_SUITE here too and everything looks good locally.

@RaimoNiskanen RaimoNiskanen added the testing currently being tested, tag is used by OTP internal CI label Jul 31, 2017
@RaimoNiskanen
Copy link
Contributor

On one of our challenged machines this fails:

FROZ
FROZ
FROZ

*** CT Error Notification 2017-07-31 23:36:54.881 ***
gen_server_SUITE:continue failed on line 485

=== Ended at 2017-07-31 23:36:54
=== Location: [{gen_server_SUITE,continue,485},
              {test_server,ts_tc,1529},
              {test_server,run_test_case_eval1,1045},
              {test_server,run_test_case_eval,977}]
=== Reason: no match of right hand side value 
                 [{<0.4970.4>,before_continue},{<0.4970.4>,continue}]
  in function  gen_server_SUITE:continue/1 (gen_server_SUITE.erl, line 485)
  in call from test_server:ts_tc/3 (test_server.erl, line 1529)
  in call from test_server:run_test_case_eval1/6 (test_server.erl, line 1045)
  in call from test_server:run_test_case_eval/9 (test_server.erl, line 977)

I'd say it is because the tested server bangs before_continue to the caller, after_continue to self() and then continue to the caller. Thereafter the server should receive after_continue from itself and bang after_continue to the caller. The caller checks for all 3 messages but did not get the last, possibly due to scheduling.

I do not understand what the started_p call is supposed to do here. Is it maybe trying to check that the continuation loop is not interrupted? But how? Or what?

Note that message ordering is only guaranteed to be preserved between pairs of processes, so a message to self() is not guaranteed to arrive before a subsequent request and reply from another process. {self(),self()} is a different pair than {self(),Other} and {Other,self()}.

If the gen_server process needs to perform an action immediately
after initialization or to break the execution of a callback into
multiple steps, it can return {continue, term()} in place of the
time-out or hibernation value, which will immediately invoke the
handle_continue/2 callback with the given term.

This provides a more accessible approach to after initialization
compared to proc_lib+enter_loop that is also guaranteed to be
safe.

It also allows callbacks that need to do lengthy or stateful work
to checkpoint the state throughout multiple iterations. This can
be useful, for example, when implementing behaviours on top of
gen_server.
@josevalim
Copy link
Contributor Author

I see the race condition. gen_server:call(started_p) is invoked before the process sends the after_continue message to itself. I have changed the tests to no longer rely on started_p as a synchronization mechanism and rather send an ack message after all continue callbacks have been invoked.

@RaimoNiskanen RaimoNiskanen merged commit 28759f8 into erlang:master Sep 6, 2017
petermm added a commit to petermm/AtomVM that referenced this pull request Aug 20, 2024
Adds GenServer support for handle_continue (https://www.erlang.org/doc/apps/stdlib/gen_server.html#c:handle_continue/2), tests are carbon copy from upstream test suite https://github.com/erlang/otp/blob/141120ab9de7e6069ee45280dc7f6a251f89e081/lib/stdlib/test/gen_server_SUITE.erl#L1012

Added to otp back in 2017: erlang/otp#1490 - often used in elixir land.

Signed-off-by: Peter M <petermm@gmail.com>
petermm added a commit to petermm/AtomVM that referenced this pull request Aug 20, 2024
Adds GenServer support for handle_continue (https://www.erlang.org/doc/apps/stdlib/gen_server.html#c:handle_continue/2), tests are carbon copy from upstream test suite https://github.com/erlang/otp/blob/141120ab9de7e6069ee45280dc7f6a251f89e081/lib/stdlib/test/gen_server_SUITE.erl#L1012

Added to otp back in 2017: erlang/otp#1490 - often used in elixir land.

Signed-off-by: Peter M <petermm@gmail.com>
petermm added a commit to petermm/AtomVM that referenced this pull request Sep 16, 2024
Adds GenServer support for handle_continue (https://www.erlang.org/doc/apps/stdlib/gen_server.html#c:handle_continue/2), tests are carbon copy from upstream test suite https://github.com/erlang/otp/blob/141120ab9de7e6069ee45280dc7f6a251f89e081/lib/stdlib/test/gen_server_SUITE.erl#L1012

Added to otp back in 2017: erlang/otp#1490 - often used in elixir land.

Signed-off-by: Peter M <petermm@gmail.com>
bettio added a commit to atomvm/AtomVM that referenced this pull request Sep 24, 2024
Support handle_continue in gen_server.erl

Adds gen_server support for handle_continue
(https://www.erlang.org/doc/apps/stdlib/gen_server.html#c:handle_continue/2),
tests are carbon copy from upstream test suite
https://github.com/erlang/otp/blob/141120ab9de7e6069ee45280dc7f6a251f89e081/lib/stdlib/test/gen_server_SUITE.erl#L1012

Added to otp back in 2017: erlang/otp#1490 - often used in elixir land.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature team:PS Assigned to OTP team PS testing currently being tested, tag is used by OTP internal CI waiting waiting for changes/input from author
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants