Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
As mentioned in part 11 there is a good idea to use timeouts when waiting for a result on a result port. But if you're going to do it in a lot of places you want to have a helper to deal with this. Here is a class that adds extension methods that are similar to the regular Choice extension method but that also adds a timeout.
1: public static class ChoiceWithTimeoutExtenstions
2: {
3: private static DispatcherQueue taskQueue = new DispatcherQueue();
4:
5: public static TimeSpan DefaultTimeout { get; set; }
6:
7: static ChoiceWithTimeoutExtenstions()
8: {
9: DefaultTimeout = TimeSpan.FromSeconds(30);
10: }
11:
12: public static Choice ChoiceWithTimeout<T>(
13: this PortSet<T, Exception> portSet,
14: Handler<T> successHandler,
15: Handler<Exception> errorHandler)
16: {
17: return portSet.ChoiceWithTimeout(
18: successHandler,
19: errorHandler,
20: DefaultTimeout);
21: }
22:
23: public static Choice ChoiceWithTimeout<T>(
24: this PortSet<T, Exception> portSet,
25: Handler<T> successHandler,
26: Handler<Exception> errorHandler,
27: TimeSpan timeout)
28: {
29: var timeoutPort = new Port<DateTime>();
30: Arbiter.Activate(
31: taskQueue,
32: timeoutPort.Receive(
33: _ => portSet.Post(
34: new TimeoutException("Timeout waiting for choice."))));
35: taskQueue.EnqueueTimer(timeout, timeoutPort);
36: return portSet.Choice(successHandler, errorHandler);
37: }
38:
39: public static Choice ChoiceWithTimeout<T>(
40: this PortSet<T, Exception> portSet,
41: Handler<T> successHandler,
42: Handler<Exception> errorHandler,
43: Handler<DateTime> timeoutHandler)
44: {
45: return portSet.ChoiceWithTimeout(
46: successHandler,
47: errorHandler,
48: timeoutHandler,
49: DefaultTimeout);
50: }
51:
52: public static Choice ChoiceWithTimeout<T>(
53: this PortSet<T, Exception> portSet,
54: Handler<T> successHandler,
55: Handler<Exception> errorHandler,
56: Handler<DateTime> timeoutHandler,
57: TimeSpan timeout)
58: {
59: var timeoutPort = new Port<DateTime>();
60: taskQueue.EnqueueTimer(timeout, timeoutPort);
61: return Arbiter.Choice(
62: portSet.Receive(successHandler),
63: portSet.Receive(errorHandler),
64: timeoutPort.Receive(timeoutHandler));
65: }
66: }
Here is a test showing how it works:
67: [TestMethod]
68: public void BasicWay_Timeout()
69: {
70: ChoiceWithTimeoutExtenstions.DefaultTimeout = TimeSpan.FromSeconds(5);
71: var port = new SuccessFailurePort();
72: Exception error = null;
73: bool successReported = false;
74: Arbiter.Activate(
75: dispatcherQueue,
76: port.ChoiceWithTimeout(s => successReported = true, e => error = e));
77: Thread.Sleep(TimeSpan.FromSeconds(10));
78: Assert.IsNotNull(error);
79: Assert.IsInstanceOfType(error, typeof(TimeoutException));
80: Assert.IsFalse(successReported);
81: port.Post(SuccessResult.Instance);
82: Thread.Sleep(TimeSpan.FromSeconds(5));
83: Assert.IsFalse(successReported);
84: }
And this is an example of usage:
85: public static IEnumerator<ITask> TypicelUse(SuccessFailurePort port)
86: {
87: yield return
88: port.ChoiceWithTimeout(
89: s => Console.WriteLine("Success: {0}", s.StatusMessage),
90: e => Console.WriteLine("Failure: {0}", e));
91: }