Timeout, the ability to execute an expression for at most a specified
amount of time, is an essential ingredient of fault-tolerant and distributed
programming. Orc accomplishes timeout using pruning and the Rwait site.
The following program runs F for at most one second, publishing its result if
available and the value 0 otherwise.
Let( F | Rwait(1000) >> 0 )
In the auction example given previously, the auction may never complete if one of the bidders does not respond. We can add a timeout so that a bidder has at most 8 seconds to provide a bid:
def auction([]) = 0 def auction(b:bs) = val bid = b.ask() | Rwait(8000) >> 0 max(bid, auction(bs))
This version of the auction is guaranteed to complete within 8 seconds.
Sometimes, rather than just yielding a default value, we would like to
determine whether an expression has timed out, and if so, perform some other
computation. To detect the timeout, we pair the result of the original
expression with true and the result of the timer with false.
Thus, if the expression does time out, then we can distinguish that case
using the boolean value.
Here, we run expression F with a time limit t. If it publishes
within the time limit, we bind its result to r and execute G.
Otherwise, we execute H.
val (r, b) = (F, true) | (Rwait(t), false) if b then G else H
Instead of using a boolean and conditional, we could use pattern matching:
val s = Some(F) | Rwait(t) >> None() s >Some(r)> G | s >None()> H
It is even possible to encapsulate timeout as a function.
def timeout(x, t) = Let(Some(x) | Rwait(t) >> None())
timeout(F, t) waits
t milliseconds for F to publish a value. If F publishes v within
the time limit, timeout returns Some(v). Otherwise, it returns
None() when the time limit is reached.
We can also apply timeout to streams. Let's
define a modified version of the repeat function as follows:
def repeatWithTimeout(f, t) = timeout(f(), t) >Some(x)> (x | repeatWithTimeout(f, t))
We call f() as before, but apply a timeout of t to the call.
If a value becomes available from f before the timeout, then the call to
timeout publishes Some(x), which we match, and then publish
x and recursively wait for further values from the stream.
However, if no value is available from f within the timeout, the call
to timeout publishes None(). Since None() does
not match the pattern, the entire expression halts, indicating that the end of the
stream has been reached.
It is also possible to achieve this behavior with the existing repeat function,
simply by changing the function passed to repeat:
def f'() = timeout(f(), t) >Some(x)> x repeat(f')