(**************************************************************************) (* *) (* Copyright (c) 2014 - 2017. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) (* *) (**************************************************************************) include Logging.Make (struct let name = "process" end) open Error_monad exception Exited of int let detach ?(prefix = "") f = Lwt_io.flush_all () >>= fun () -> match Lwt_unix.fork () with | 0 -> Random.self_init () ; let template = Format.asprintf "%s$(section): $(message)" prefix in let logger = Lwt_log.channel ~template ~close_mode:`Keep ~channel:Lwt_io.stderr () in Logging.init (Manual logger) ; Lwt_main.run begin lwt_log_notice "PID: %d" (Unix.getpid ()) >>= fun () -> f () end ; exit 0 | pid -> Lwt.catch (fun () -> Lwt_unix.waitpid [] pid >>= function | (_,Lwt_unix.WEXITED 0) -> Lwt.return_unit | (_,Lwt_unix.WEXITED n) -> Lwt.fail (Exited n) | (_,Lwt_unix.WSIGNALED _) | (_,Lwt_unix.WSTOPPED _) -> Lwt.fail Exit) (function | Lwt.Canceled -> Unix.kill pid Sys.sigkill ; Lwt.return_unit | exn -> Lwt.fail exn) let handle_error f = Lwt.catch f (fun exn -> Lwt.return (error_exn exn)) >>= function | Ok () -> Lwt.return_unit | Error err -> lwt_log_error "%a" Error_monad.pp_print_error err >>= fun () -> exit 1 let rec wait processes = Lwt.catch (fun () -> Lwt.nchoose_split processes >>= function | (_, []) -> lwt_log_notice "All done!" | (_, processes) -> wait processes) (function | Exited n -> lwt_log_notice "Early error!" >>= fun () -> List.iter Lwt.cancel processes ; Lwt.catch (fun () -> Lwt.join processes) (fun _ -> Lwt.return_unit) >>= fun () -> lwt_log_notice "A process finished with error %d !" n >>= fun () -> Pervasives.exit n | exn -> lwt_log_notice "Unexpected error!%a" Error_monad.pp_exn exn >>= fun () -> List.iter Lwt.cancel processes ; Lwt.catch (fun () -> Lwt.join processes) (fun _ -> Lwt.return_unit) >>= fun () -> Pervasives.exit 2)