Print Page | Close Window

Coroutine Error Handling

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=2565
Printed Date: 08-May-2025 at 7:54am


Topic: Coroutine Error Handling
Posted By: ken.nelson
Subject: Coroutine Error Handling
Date Posted: 16-Mar-2011 at 8:05am
Is it necessary to error check each coroutine operation's error state after each yield return or is it eoungh to handle errors in the Coroutine completed callback?  (Is the red highlighted code below necessary?)
 
Without the use of a Coroutine, my code would look something like the following, with error checked after each async call has completed:
 

private void LoadData() {

     em.Customers.Where().ExecuteAsync((customerArgs) =>
     {
          if (customerArgs.HasError) { // handle error }
          else
          {
               em.Orders.Where().ExecuteAsync((orderArgs) =>
               {
                    if (orderArgs.HasError) { // handle error }
                    else
                    {
 
                    }
               });
          }
     });
}
 
Translating to Coroutine, my code is:
 

private void LoadData()
{
     Coroutine.Start(CoroutineActions, (completed) =>
     {
          if (completed.HasError) { // handle error }
          else
          {
 
          }
     });
}
 
private IEnumerable<INotifyCompleted> CoroutineActions()
{
     var op1 = em.Customers.Where().ExecuteAsync();
     yield return op1;
 
     // Do I have to continue to error check after each async operation, or
     // is it ok to skip this?
     if (op1.HasError) { // handle error }
     else
     {
          var op2 = em.Orders.Where().ExecuteAsync();
          yield return op2;
     }
}
 



Replies:
Posted By: sbelini
Date Posted: 16-Mar-2011 at 12:13pm
Hi Ken,
 
It is always a good idea, and the developers responsability, to check for errors.
 
On a coroutine operation you should check for errors before yielding to the Coroutine consumer:
 
////////////////////////////////////////////////////////////////////////////////////////
private IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine() {

  var userId = CurrentUser.UserId;

  var allCustOperation = Manager.Customers.ExecuteAsync();

  // event handler
  var allCustOperation.Completed += (s1, args1) => {
    if (args1.HasError) HandleError(args1);
  };

  yield return allCustOperation; // SUSPEND
  // more code
}
////////////////////////////////////////////////////////////////////////////////////////
 
or
 
////////////////////////////////////////////////////////////////////////////////////////
private IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine() {
  var allCustOperation = Manager.Customers.ExecuteAsync(
     // Callback checks for error
     op => { if (op.HasError) HandleError(op); }
    );

  yield return allCustOperation; 
  // more code
}
////////////////////////////////////////////////////////////////////////////////////////
 
 
If an error occurs, you can let the error bubble up to the outer Coroutine or you can take care of the exception and mark the error as handled:
 
op. http://drc.ideablade.com/ApiDocumentation/webframe.html?IdeaBlade.EntityModel~IdeaBlade.EntityModel.AsyncEventArgs~MarkErrorAsHandled.html - MarkErrorAsHandled ();
 
You will also find this information in our http://drc.ideablade.com/xwiki/bin/view/Documentation/Asynchronous-Coroutine-Errors - DevForce Resource Center .
 
Regards,
   Silvio.


Posted By: mikewishart
Date Posted: 17-Mar-2011 at 9:38am
Ken, write yourself some extension methods such as:

    /// <summary>
    /// Same as ExecuteAsync() except it tests for an error before returning the result
    /// </summary>
    public static EntityQueryOperation<T> ExecuteAsyncResult<T>(this IEntityQuery<T> query,
      Action<IEnumerable<T>> userCallback)
    {
      return query.ExecuteAsync(op => CheckExecuteAsyncResult(op, userCallback), null);
    }

    /// <summary>
    /// Same as ExecuteAsync() except it tests for an error before returning the result
    /// </summary>
    public static EntityQueryOperation<T> ExecuteAsyncResult<T>(this IEntityQuery<T> query,
      Action<IEnumerable<T>, object> userCallback, object userState)
    {
      return query.ExecuteAsync(op => CheckExecuteAsyncResult(op, r => userCallback(r, op.UserState)), userState);
    }

    private static void CheckExecuteAsyncResult<T>(EntityQueryOperation<T> op,
      Action<IEnumerable<T>> userCallback)
    {
      if (op.HasError)
        throw new Exception(op.Error.Message);

      userCallback(op.Results);
    }



Posted By: ken.nelson
Date Posted: 17-Mar-2011 at 12:50pm
This was more of a question of, "what is DevForce doing under the hood automatically?".  From the sound of it, my conclusion is that DevForce is not checking the error state of the each async operation while executing in a coroutine.  And this is perfectly ok, I just wasn't sure if it was necessary to check for errors after each operation or if it was already being done under the hood.
 
Thanks!


Posted By: kimj
Date Posted: 18-Mar-2011 at 5:02pm

DevForce does actually check for errors after each async operation, and does not call subsequent operations in the iterator block if a prior one failed, unless you've marked the error as handled.  If you set up a handler for the Coroutine completed you can see there if an error occurred, plus all the "Notifications" for each async operation up to and including the operation which failed.  You don't need to include error checking within your iterator unless you want to, or if you will be marking the error as handled so that subsquent operations can run.




Print Page | Close Window