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

graceful shutdown #178

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

vishalchangrani
Copy link

This change is to allow for a graceful shutdown of the Mochiweb server.

  1. A new option - shutdown_delay has been added. It represents the number of milliseconds to wait before allowing the mochiweb_socket_server to be terminated.
  2. A new gen_server call - prep_stop has been added which removes the listener from the socket server.
  3. When a stop is issued, the server listen socket is closed and the mochiweb_socket_server waits uptil shutdown_delay for the activesockets to go down to zero.
  4. A unit test - graceful_shutdown_test_fun has been added. It creates two clients each of which issues a request sequentially with a delay.

@@ -38,6 +38,9 @@ client_fun(Socket, [{send_pid, To} | Cmds]) ->
To ! {client, self()},
client_fun(Socket, Cmds);
client_fun(Socket, [{send, Data, Tester} | Cmds]) ->
client_fun(Socket, [{send, Data, Tester, 0} | Cmds]);
client_fun(Socket, [{send, Data, Tester, Delay} | Cmds]) ->
timer:sleep(Delay),
Copy link
Member

Choose a reason for hiding this comment

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

It's not good to have tests that sleep, they can cause the test runs to take much longer than they should and they can intermittently pass or fail depending on external factors (e.g. the specs or load on the system running the tests). It's best to have code that doesn't require the wall clock to work, or at least use mocking when testing it to avoid any sleeping.

close_listen_socket(State),
State1 = State#mochiweb_socket_server{shutdown_notify_pid=From, acceptor_pool_size=0},
% Reply will be given when active_socket count goes to 0
{noreply, State1};
Copy link
Author

Choose a reason for hiding this comment

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

Removed the polling logic by using a noreply response and a reply when active_sockets become 0.

@vishalchangrani
Copy link
Author

I have made another commit to incorporate the changes you mentioned @etrepum - Removing of the polling logic from the source and the timer:sleep in the unit test. Please can you review the changes and merge to master? thanks.

@@ -60,12 +61,15 @@ set(Name, Property, _Value) ->
[Name, Property]).

stop(Name) when is_atom(Name) orelse is_pid(Name) ->
gen_server:call(Name, stop);
gen_server:call(Name, stop);

Choose a reason for hiding this comment

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

was this change on purpose?

stop({Scope, Name}) when Scope =:= local orelse Scope =:= global ->
stop(Name);
stop(Options) ->
State = parse_options(Options),
stop(State#mochiweb_socket_server.name).
stop(Name, Timeout) when is_atom(Name) orelse is_pid(Name) andalso is_integer(Timeout) ->

Choose a reason for hiding this comment

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

andalso has precedence over orelse. Therefore, this guard will be true for:
is_atom(Name) (independently of Timeout's type)
or
is_pid(Name) andalso is_integer(Timeout)

Is that the expected behaviour? I believe it should be:

Suggested change
stop(Name, Timeout) when is_atom(Name) orelse is_pid(Name) andalso is_integer(Timeout) ->
stop(Name, Timeout) when (is_atom(Name) orelse is_pid(Name)) andalso is_integer(Timeout) ->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants