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.
Sometimes you work with an API that returns a Choice. If you want to add a timeout to any choice we need to extend the set of extension methods I introduced in part 22 with this:
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 WithTimeout(
13: this Choice choice,
14: Handler<DateTime> timeoutHandler)
15: {
16: return choice.WithTimeout(timeoutHandler, DefaultTimeout);
17: }
18:
19: public static Choice WithTimeout(
20: this Choice choice,
21: Handler<DateTime> timeoutHandler,
22: TimeSpan timeout)
23: {
24: var choiceCompletedPort = new Port<EmptyValue>();
25: Arbiter.Activate(
26: taskQueue,
27: Arbiter.FromIteratorHandler(
28: () => ExecuteChoice(choice, choiceCompletedPort)));
29: var timeoutPort = new Port<DateTime>();
30: taskQueue.EnqueueTimer(timeout, timeoutPort);
31:
32: return Arbiter.Choice(
33: choiceCompletedPort.Receive(),
34: timeoutPort.Receive(dt => timeoutHandler(dt)));
35: }
36:
37: private static IEnumerator<ITask> ExecuteChoice(
38: Choice choice,
39: Port<EmptyValue> port)
40: {
41: yield return choice;
42: port.Post(EmptyValue.SharedInstance);
43: }
44: }
And the test to show how it works:
45: [TestMethod]
46: public void AddingTimeoutToChoice_Timeout()
47: {
48: ChoiceWithTimeoutExtenstions.DefaultTimeout = TimeSpan.FromSeconds(5);
49: var port = new SuccessFailurePort();
50: Exception error = null;
51: bool successReported = false;
52: Arbiter.Activate(
53: dispatcherQueue,
54: port.Choice(s => successReported = true, e => error = e)
55: .WithTimeout(_ => port.Post(new TimeoutException())));
56: Thread.Sleep(TimeSpan.FromSeconds(10));
57: Assert.IsNotNull(error);
58: Assert.IsInstanceOfType(error, typeof(TimeoutException));
59: Assert.IsFalse(successReported);
60: port.Post(SuccessResult.Instance);
61: Thread.Sleep(TimeSpan.FromSeconds(5));
62: Assert.IsFalse(successReported);
63: }
And some example code:
64: public static IEnumerator<ITask> TimeoutOnAnyChoice<T1, T2>(
65: PortSet<T1, T2> port)
66: {
67: yield return
68: port.Choice(
69: a => Console.WriteLine("A: {0}", a),
70: b => Console.WriteLine("B: {0}", b)).WithTimeout(
71: _ => port.PostUnknownType(
72: new TimeoutException("Timeout waiting for choice.")));
73: }