quit a little more gracefully when interrupted (SIGINT, SIGTERM)
This commit is contained in:
parent
e355bac41c
commit
e160156b78
|
@ -14,25 +14,21 @@ type config = {
|
||||||
notify : [`ready | `stopping] -> unit;
|
notify : [`ready | `stopping] -> unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ping_wheel = Connection.t Wheel.t
|
let bind_server
|
||||||
|
|
||||||
let listener
|
|
||||||
~(port : int)
|
~(port : int)
|
||||||
~(listen_backlog : int)
|
~(listen_backlog : int)
|
||||||
~(on_ready : unit -> unit)
|
: fd Lwt.t =
|
||||||
: (fd * sockaddr) Lwt_stream.t =
|
let fd = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
|
||||||
let sock : fd Lwt.t =
|
Lwt_unix.setsockopt fd SO_KEEPALIVE false;
|
||||||
let fd = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
|
Lwt_unix.setsockopt fd SO_REUSEPORT false;
|
||||||
Lwt_unix.setsockopt fd SO_KEEPALIVE false;
|
let srv_adr = Unix.ADDR_INET (Unix.inet_addr_any, port) in
|
||||||
Lwt_unix.setsockopt fd SO_REUSEPORT false;
|
let* () = Lwt_unix.bind fd srv_adr in
|
||||||
let srv_adr = Unix.ADDR_INET (Unix.inet_addr_any, port) in
|
Lwt_unix.listen fd listen_backlog;
|
||||||
let* () = Lwt_unix.bind fd srv_adr in
|
info (fun m -> m "listening on %a" pp_sockaddr srv_adr);
|
||||||
Lwt_unix.listen fd listen_backlog;
|
Lwt.return fd
|
||||||
on_ready ();
|
|
||||||
info (fun m -> m "listening on %a" pp_sockaddr srv_adr);
|
let accepts (fd : fd) : (fd * sockaddr) Lwt_stream.t =
|
||||||
Lwt.return fd
|
let accept () = Lwt_unix.accept fd >>= Lwt.return_some in
|
||||||
in
|
|
||||||
let accept () = sock >>= Lwt_unix.accept >|= Option.some in
|
|
||||||
Lwt_stream.from accept
|
Lwt_stream.from accept
|
||||||
|
|
||||||
let reader (fd : fd) : Msg.t Lwt_stream.t =
|
let reader (fd : fd) : Msg.t Lwt_stream.t =
|
||||||
|
@ -81,7 +77,7 @@ let handle_client
|
||||||
(conn_addr : sockaddr)
|
(conn_addr : sockaddr)
|
||||||
~(server_info : Server_info.t)
|
~(server_info : Server_info.t)
|
||||||
~(router : Router.t)
|
~(router : Router.t)
|
||||||
~(ping_wheel : ping_wheel)
|
~(ping_wheel : Connection.t Wheel.t)
|
||||||
=
|
=
|
||||||
info (fun m -> m "new connection %a" pp_sockaddr conn_addr);
|
info (fun m -> m "new connection %a" pp_sockaddr conn_addr);
|
||||||
let conn : Connection.t =
|
let conn : Connection.t =
|
||||||
|
@ -107,6 +103,24 @@ let handle_client
|
||||||
(fun e -> error (fun m -> m "%a:@ %a" pp_sockaddr conn_addr Fmt.exn e));
|
(fun e -> error (fun m -> m "%a:@ %a" pp_sockaddr conn_addr Fmt.exn e));
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let interval dt =
|
||||||
|
let tick () =
|
||||||
|
let* () = Lwt_unix.sleep dt in
|
||||||
|
Lwt.return_some ()
|
||||||
|
in
|
||||||
|
Lwt_stream.from tick
|
||||||
|
|
||||||
|
let interrupt () =
|
||||||
|
let signal, signal_waiter = Lwt.wait () in
|
||||||
|
let on_signal num =
|
||||||
|
trace (fun m -> m "caught signal %d" num);
|
||||||
|
try Lwt.wakeup signal_waiter () with
|
||||||
|
Invalid_argument _ -> failwith "unceremoniously exiting"
|
||||||
|
in
|
||||||
|
Lwt_unix.on_signal (2 (* SIGINT *)) on_signal |> ignore;
|
||||||
|
Lwt_unix.on_signal (15 (* SIGTERM *)) on_signal |> ignore;
|
||||||
|
signal
|
||||||
|
|
||||||
let run {
|
let run {
|
||||||
port;
|
port;
|
||||||
listen_backlog;
|
listen_backlog;
|
||||||
|
@ -137,6 +151,13 @@ let run {
|
||||||
info (fun m -> m "version:@ %s" server_info.version);
|
info (fun m -> m "version:@ %s" server_info.version);
|
||||||
info (fun m -> m "created:@ %s" server_info.created);
|
info (fun m -> m "created:@ %s" server_info.created);
|
||||||
|
|
||||||
|
let* server : fd =
|
||||||
|
bind_server
|
||||||
|
~port
|
||||||
|
~listen_backlog
|
||||||
|
in
|
||||||
|
notify `ready;
|
||||||
|
|
||||||
let router : Router.t =
|
let router : Router.t =
|
||||||
Router.make
|
Router.make
|
||||||
~whowas_history_len
|
~whowas_history_len
|
||||||
|
@ -147,40 +168,40 @@ let run {
|
||||||
ping_interval
|
ping_interval
|
||||||
in
|
in
|
||||||
|
|
||||||
let on_tick () =
|
let ping conn =
|
||||||
(* trace (fun m -> m "tick"); *)
|
match Connection.on_ping conn with
|
||||||
List.iter
|
| Ok () -> Wheel.add ping_wheel conn
|
||||||
(fun conn ->
|
| Error _ -> Connection.close conn ~reason:"Connection timeout"
|
||||||
match Connection.on_ping conn with
|
|
||||||
| Ok () -> Wheel.add ping_wheel conn
|
|
||||||
| Error () -> Connection.close conn ~reason:"Connection timed out")
|
|
||||||
(Wheel.tick ping_wheel)
|
|
||||||
in
|
in
|
||||||
|
|
||||||
let pinger_promise =
|
let pinger_promise =
|
||||||
Lwt_stream.iter
|
Lwt_stream.iter
|
||||||
on_tick
|
(fun () ->
|
||||||
(Lwt_stream.from @@ fun () ->
|
List.iter ping
|
||||||
let* () = Lwt_unix.sleep 1.0 in
|
(Wheel.tick ping_wheel))
|
||||||
Lwt.return_some ())
|
(interval 1.0)
|
||||||
in
|
|
||||||
|
|
||||||
let on_con (fd, adr) =
|
|
||||||
handle_client fd adr
|
|
||||||
~server_info
|
|
||||||
~router
|
|
||||||
~ping_wheel
|
|
||||||
in
|
in
|
||||||
|
|
||||||
let listener_promise =
|
let listener_promise =
|
||||||
Lwt_stream.iter
|
Lwt_stream.iter
|
||||||
on_con
|
(fun (fd, addr) ->
|
||||||
(listener
|
handle_client fd addr
|
||||||
~port
|
~server_info
|
||||||
~listen_backlog
|
~router
|
||||||
~on_ready:(fun () -> notify `ready))
|
~ping_wheel)
|
||||||
|
(accepts server)
|
||||||
in
|
in
|
||||||
|
|
||||||
(* TODO: graceful cleanup on ctrl-c *)
|
let* () =
|
||||||
|
Lwt.pick [
|
||||||
|
listener_promise <?> pinger_promise;
|
||||||
|
interrupt ()
|
||||||
|
]
|
||||||
|
in
|
||||||
|
notify `stopping;
|
||||||
|
|
||||||
|
(* TODO: send QUIT to all connections *)
|
||||||
|
|
||||||
|
info (fun m -> m "shutting down");
|
||||||
|
Lwt_unix.close server
|
||||||
|
|
||||||
listener_promise <&> pinger_promise
|
|
||||||
|
|
Loading…
Reference in New Issue