[E-Lang] remote comms
Marc Stiegler
marcs@skyhunter.com
Sun, 1 Apr 2001 18:25:03 -0700
> Our (speaking for Dean and myself) recommendations for using remote
> references equate to recreating a LiveRef from a SturdyRef at the
> beginning of every small-scale transaction. We've hidden from the
> developers the problem of ensuring that there's a live connection to
> each server that a component relies on. We've provided them with a
> single call that asks for a proxy for any particular service they rely
> on, and recommended that they re-use it throughout a transaction, but
> ask for a new copy when they receive a new request.
>
> One of the pieces we haven't implemented yet that these developers will
> definitely need is a simple invocation for time-out logic for
> practically all remote messages. I think this is the same need that
> zooko is talking about with his impatience logic. In our application,
> all (user-initiated) requests will have explicit requirements-driven
> need to timeout and return a default answer. In our context (making
> access control decisions) the default answer is that if we haven't
> received the information to make a positive decision in a certain amount
> of time, we forbid access. The distributed components are working
> together to reach this decision, so it could just be the code that talks
> to the user that times out. We'll probably have time-outs in most of
> the components so they take a limited amount of time and don't waste
> computrons on hard questions that the requester has given up on.
>
> My intuition today is that it should be simple to build both promises
> that have an explicit time-out and ones that don't. The latter
> shouldn't time out any sooner than the underlying mechanisms (e.g. TCP)
require.
Since this was the second comment that said, we need easy timeout (and other
impatience policies) at a higher level, I thought I'd give everyone the code
to implement a timeout at the programmer level.
It turns out not to have been quite as easy as I'd thought (I had allowed
myself to become confused about multi-vow when-catch behavior). But it is
still easy.
To get set up, I have created 2 functions. promiseFirstResolved returns a
promise for the first resolution in a list of promises (so if the first
resolution is to break a promise, this propogates the break). And
promiseTimeout uses the E Timer object to smash the promise it returns,
after a specified interval. So if you give promiseFirstResolved a list of
promises that includes a timeout and a promise for something you want "in a
timely fashion", you either get the fulfillment of the promise within the
time period or you get a timeout broken promise.
Once you have set up these functions, a timed-out wait for an object is a
normal single-argument when-catch. The timeout user only needs to know how
to use promiseFirstResolved and promiseTimeout together to build tons of
impatient when-catch clauses.
I broke this into these pieces because you can reuse promiseFirstResolved to
set up arbitrarily complex impatience policies. Either replace the
promiseTimeout function with a complex function, or add additional
conditions to the list given to promiseFirstResolved, any one of which can
terminate the wait by smashing its promise.
Anyway, this is a nice piece, and I will probably include it in Walnut. Both
promiseFirstResolved and promiseTimeout are handy utilities for more than
just this one purpose. Of course, markm will probably be annoyed with this
since I didn't use a "thunk" in promiseFirstResolved :-) I'm just an old
FORTRAN hacker at the end of the day :-)
Code below. Not thoroughly tested :-)
--marcs
? def promiseFirstResolved(listOfPromises) :any {
> var isFirst := true
> def [firstPromise, firstResolver] := PromiseMaker()
> for eachPromise in listOfPromises {
> when (eachPromise) -> done(each) {
> if (isFirst) {
> isFirst := false
> firstResolver resolve(each)
> }
> } catch err {
> if (isFirst) {
> isFirst := false
> firstResolver smash(err)
> }
> }
> }
> firstPromise
> }
# value: <promiseFirstResolved>
? def promiseTimeout(secondsToWait) :any {
> def [timeoutPromise, timeoutResolver] := PromiseMaker()
> def timeout() {timeoutResolver smash("Timeout")}
> <unsafe:org.erights.e.extern.timer.Timer> theTimer() after(
> 1000*secondsToWait,
> timeout)
> timeoutPromise
> }
# value: <promiseTimeout>
? def [marcPromise,marcResolver] := PromiseMaker()
# value: [<Eventual ref>, <Open Resolver>]
# Note this is just a when-catch with a list of promises in
promiseFirstResolved
? when (promiseFirstResolved([marcPromise, promiseTimeout(10)])) ->
done(result) {
> println("promise fulfilled in time" + result)
> } catch err {println("promise broken: "+ err)}
?
#(wait 11 seconds, hit Enter in Elmer--in E it would go on the event queue,
no Enter required :-)
promise broken: <StringException: Timeout>