Timeout Reading From Stdin With Promises using async

Task

Concurrency & Parallelism / Single-Threaded Concurrency / Timeout Reading From Stdin With Promises

Prompt the user to input some text on stdin - if the user does not finish before the timeout, abort.

Opam Packages Used

  • async Tested with version: 0.17.0 — Used libraries: async

Code

Async is Jane Street's concurrent programming library, similar to Lwt but with different design choices and better integration with Core/Base libraries.

'a Deferred.t is Async's equivalent to Lwt's promises - it represents a value that will be available in the future.

open Async

let (let*) = Async.(>>=)

Attempts to read a line from standard input. Reader.read_line returns `Ok string when successful, or `Eof when end-of-file is reached.

Note: Core.Lazy.force is needed because stdin is initialized lazily to allow for customization before first use.

let read_name () : string option Deferred.t =
  let* s =
    Reader.read_line (Core.Lazy.force Reader.stdin)
  in
  match s with
  | `Eof -> Deferred.return (Some "")
  | `Ok str -> Deferred.return (Some str)

Async.after creates a deferred that completes after specified duration (in this case, 6 seconds).

let timeout () : string option Deferred.t =
  let* () = after (Core.sec 6.0) in
  Deferred.return None

We create two concurrent operations: reading input and timeout, then use Deferred.any to race them against each other, and handle the result with Async.upon (similar to .then in JavaScript promises).

let () =
  print_endline "Enter your name (don't take too long)";
  let race =
    Deferred.any [ read_name (); timeout () ]
  in
  upon race (fun r ->
    (match r with
    | Some n -> Async_unix.Print.printf "Hello %s\n" n
    | None -> Async_unix.Print.print_endline "Too slow!");

The explicit Async.exit is needed because the Async event-loop (Scheduler.go) never returns.

    ignore (Async.exit 0));
  Core.never_returns (Scheduler.go ())

Discussion

Async is part of Jane Street's set of libraries and depends on Base and Core. If you are already using Core you may well prefer Async over Lwt for its better "fit".

Note: this example could be improved by adding error handling and/or handling of properly closing stdin in case of timeout.

Recipe not working? Comments not clear or out of date?

Open an issue or contribute to this recipe!

Other Recipes for this Task