Being Cellfish

Stuff I wished I've found in some blog (and sometimes did)

August, 2011

Change of Address
This blog has moved to blog.cellfish.se.
Posts
  • Being Cellfish

    CCR tips and tricks - summary

    • 4 Comments

    So it turned out to be an advent calendar in the middle of the summer... Here is an overview:

    Prologue
    1, 2, 24, 25 - writing unit tests for CCR
    3, 4, 21 - causalities
    5 - SuccessFailure ports
    6 - CCR APIs
    7 - 4 ways to receive
    8 - scatter gather
    9, 10 - yielding on the right thing
    11 - result ports
    12 - problems when reusing ports
    13 - Receive with no handler
    14 - calling asynchronous APIs from CCR
    15, 16 - calling synchronous APIs from CCR
    17 - abort port
    18 - exclusive handlers
    19, 20 - throttling events
    22, 23 - adding timeouts to receiver tasks

    I'm sure there will be more tips and tricks for CCR in the future.

  • Being Cellfish

    CCR tips and tricks - part 22

    • 0 Comments

    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: }
    
  • Being Cellfish

    CCR tips and tricks - part 23

    • 0 Comments

    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: }
    
  • Being Cellfish

    CCR tips and tricks - part 24

    • 0 Comments

    Today I'll show you an example of how can use the pattern used in part 23 to make the utilities from part 1 look a little different and also work for any number of branches in a choice. But there is an important consequence of this.

      1: public static void CompleteSynchronously(this Choice choice)
      2: {
      3:     var choiceCompletedPort = new Port<EmptyValue>();
      4:     Arbiter.Activate(
      5:         taskQueue,
      6:         Arbiter.FromIteratorHandler(
      7:             () => ExecuteChoice(choice, choiceCompletedPort)));
      8:     using (var mre = new ManualResetEvent(false))
      9:     {
     10:         Arbiter.Activate(
     11:             taskQueue, 
     12:             choiceCompletedPort.Receive(_ => mre.Set()));
     13:         mre.WaitOne();
     14:     }
     15: }
    

    While this looks neat there is a problem with this implementation that was covered in part 7. There is a race condition in that when the choice completes it has only scheduled the choice handler for execution. So ExecuteChoice may post to its completion port which means that the handler that sets the event is also scheduled for execution. Hence we have two handlers scheduled for execution and we do not know which once will execute first nor will be know if the WaitOne (line 13) will be released before the choice handler completes. So this solution does not work well if you need 100% guarantee that the choice handler has executed when CompleteSynchronously returns but this method works if you want something that waits until the choice is resolved and a handler scheduled.

Page 1 of 1 (4 items)