Category Archives: Delegate

Cinchoo – Abortable long running aync task

Introduction

In .NET, there are number of ways you can start asynchronous long running tasks by using Thread / Task / ThreadPool. Every approach has pros and cons to it. Please refer MSDN for more information about them. In this article I’m going to elobarate about method exists in Cinchoo framework where you can start abortable long running task asnychrously.

First, each windows application has a single main thread it uses to render the window / execute main task, process events and execute custom code. In a single threaded environment, any long running tasks will block the main thread. In particlular it will block the main UI thread and the application becomes unresponsive in Windows application.

Cinchoo simplifies the model to execute a long running tasks asynchronously and gives control to the caller to abort it anytime. Besides the standard behaviour, it offers few useful features like number of retries in case of failure, timeout period via the API. Alright lets cut to the chase on to how to use them using the code.

Download the Latest Cinchoo Binary Here. (Nuget Command: Install-Package Cinchoo)

Using the Code

The API is exposed via ChoActionEx class. The signature of the API looks below

public static class ChoActionEx
{
    public static ChoAbortableAsyncResult RunAsync(this Action action, ChoAbortableAsyncCallback callback = null, object state = null, int timeout = -1, int maxNoOfRetry = 0, int sleepBetweenRetry = 5000);
}

Where

  • action – A long running task method.
  • callback – References a method to be called when a corresponding asynchronous operation completes.
  • state – A user-defined object that qualifies or contains information about an asynchronous operation.
  • timeout – A time-out value in milliseconds. -1, infinite.
  • maxNoOfRetry – Maximum number of retry attempt made in case of failure.
  • sleepBetweenRetry – Number of milliseconds to sleep between retry. Default is 5000 ms.

This API method returns ChoAbortableAsyncResult object. This encapsulates the results of an asynchronous operation on a delegate. It exposes the below members

  • AsyncState – Gets the object provided in the ‘state’ parameter of a RunAsync method call.
  • AsyncWaitHandle – Gets a WaitHandle that encapsulates Win32 synchronization handles, and allows the implementation of various synchronization schemes.
  • CompletedSynchronously – Gets a value indicating whether the RunAsync call completed synchronously.
  • IsAborted – Gets a value indicating whether the server has aborted the call.
  • IsCompleted – Gets a value indicating whether the server has completed the call.
  • IsRetryAttempt – Gets a value indicating whether the server has retried the call.
  • IsTimeout – Gets a value indicating whether the method has completed with the timeout.
  • Result – Gets the result value from the async call if any.
  • RetryCount – Gets a value of the number of retry attempt made by the server.
  • Exception – Gets any exception captured during task execution.
  • CanContinue – Gets or Sets where to continue the retry.
  • EndInvoke() – Retrieves the return value of the asynchronous operation. If the asynchronous operation has not been completed, this function will block until the result is available.
  • Abort() – Abort the currently executing asynchrounous call.

Sample #1

Below sample shows how to execute a method asynchrounously, wait for it to complete.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine();
 
        //Run method async, wait for it to complete
        Console.WriteLine("TEST #1: Run method, wait for it to complete...");
        ChoAbortableAsyncResult r = ChoActionEx.RunAsync(LongRunningTask);
        Console.WriteLine("Waiting for worker thread to complete.");
        r.EndInvoke();
        Console.WriteLine();
    }
 
    private static void LongRunningTask()
    {
        Console.WriteLine("Starting task... (Sleeping for 10 secs)");
        Console.WriteLine("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10 * 1000);
        Console.WriteLine("Task completed.");
    }
}

Sample #2

Below sample shows how to execute a method asynchrounously, abort it after 5 secs.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine();

        //Run method async, abort it after 5 secs
        Console.WriteLine("TEST #2: Run method, abort after 5 secs...");
        ChoAbortableAsyncResult r1 = ChoActionEx.RunAsync(LongRunningTask);
        Console.WriteLine("Waiting for 5 secs...");
        Thread.Sleep(5000);
        Console.WriteLine("Aborting working thread.");
        r1.Abort();
        Console.WriteLine();
    }
 
    private static void LongRunningTask()
    {
        Console.WriteLine("Starting task... (Sleeping for 10 secs)");
        Console.WriteLine("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10 * 1000);
        Console.WriteLine("Task completed.");
    }
}

Sample #3

Below sample shows how to execute a method asynchrounously, timeout after 5 secs.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine();

        //Run method async, with timeout 5 secs
        Console.WriteLine("TEST #3: Run method with 5 secs timeout...");
        ChoAbortableAsyncResult r2 = ChoActionEx.RunAsync(LongRunningTask, null, null, 5000);
        Console.WriteLine("Waiting for worker thread to complete or timeout.");
        try
        {
            r2.EndInvoke();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        Console.WriteLine();
    }
 
    private static void LongRunningTask()
    {
        Console.WriteLine("Starting task... (Sleeping for 10 secs)");
        Console.WriteLine("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10 * 1000);
        Console.WriteLine("Task completed.");
    }
}

Sample #4

Below sample shows how to execute a method asynchrounously, retry couple of attempts.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine();

        //Run a exception thrown method async 
        Console.WriteLine("TEST #4: Run method with 2 retries...");
        ChoAbortableAsyncResult r3 = ChoActionEx.RunAsync(LongRunningTaskWithException, null, null, -1, 2, 5000);
        Console.WriteLine("Waiting for worker thread to complete.");
        try
        {
            r3.EndInvoke();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        Console.WriteLine();
    }
    
    private static void LongRunningTaskWithException()
    {
        Console.WriteLine("Starting task... (Sleeping for 10 secs)");
        Console.WriteLine("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10 * 1000);
        throw new ApplicationException("Test task exception.");
    }
}

Sample #5

Below sample shows how to execute a method asynchrounously, cancel it in the callback.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine();

        Console.WriteLine("TEST #5: Run method with 2 retries, but cancel the retry on callback...");
        ChoAbortableAsyncResult r5 = ChoActionEx.RunAsync(LongRunningTaskWithException, (t) =>
        {
            ChoAbortableAsyncResult t1 = t as ChoAbortableAsyncResult;
            Console.WriteLine("Canceling the task...");
            if (t1.Exception != null)
                t1.CanContinue = false;
        }, null, -1, 2, 5000);
        try
        {
            r5.EndInvoke();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        Console.WriteLine();
    }
    
    private static void LongRunningTaskWithException()
    {
        Console.WriteLine("Starting task... (Sleeping for 10 secs)");
        Console.WriteLine("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10 * 1000);
        throw new ApplicationException("Test task exception.");
    }
}
Advertisements

Cinchoo – Delegate.WaitFor(), Extension Method

Here I’ll talk about WaitFor extension method. This extension method used to run a method with finite number of retries if it failed to run at first time and/or in a finite time frame. It provides most of Action and Func delgates overloads.

1. Add reference to Cinchoo.Core.dll assembly

2. Namespace Cinchoo.Core

Sample 1:

Below are the list of overloads for Func<T> delegate, Cinchoo provides these overloads almost all the Func’s and Action’s.

public static TResult WaitFor(this Func func);
public static TResult WaitFor(this Func func, int timeout);
public static TResult WaitFor(this Func func, int timeout, int maxNoOfRetry);
public static TResult WaitFor(this Func func, int timeout, int maxNoOfRetry, int sleepBetweenRetry);

Below sample shows you how to run a  Func<T> delegate method using WaitFor() extension method.

class Program
{
    static void Main(string[] args)
    {
		Func f1 = () =&gt;
			{
				System.Threading.Thread.Sleep(1);
                Console.WriteLine(&quot;Running method...&quot;);
				return 1;
			};

        Console.WriteLine(&quot;Output: {0}&quot;.FormatString(f1.WaitFor()));
	}
}

When you run the above code, the output will be

Running method...
Output: 1
Press any key to continue . . .

Sample 2:

In this example, I’ll show you the way of invoking a method with timeout (1000ms) parameter. It throws a timeout exception, as the method takes more time to execute than timeout (1000 ms) period.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Func f1 = () =&gt;
                {
                    System.Threading.Thread.Sleep(5000);
                    Console.WriteLine(&quot;Running method...&quot;);
                    return 1;
                };

            Console.WriteLine(&quot;Output: {0}&quot;.FormatString(f1.WaitFor(1000)));
        }
        catch (Exception ex)
        {
            Console.WriteLine(&quot;Error: {0}&quot;.FormatString(ex.Message));
        }
	}
}

When you run the above code, the output will be

Error: Timeout [1000 ms] elapsed prior to completion of the method [Target: , Metho
d: Int32 b__0()].
Press any key to continue . . .

Sample 3:

In here, we will see how a method with an error is executed for number of times with one of the WaitFor overload.

static void Main(string[] args)
{
    try
    {
        Func&lt;int&gt; f1 = () =&gt;
            {
                System.Threading.Thread.Sleep(10);
                throw new ApplicationException(&quot;Communication error.&quot;);
            };

        Console.WriteLine(&quot;Output: {0}&quot;.FormatString(f1.WaitFor(Timeout.Infinite, 3)));
    }
    catch (Exception ex)
    {
        Console.WriteLine(&quot;Error: {0}&quot;.FormatString(ex.Message));
    }
}

When you run the above code, the output will be

Error: Exception(s) occurred : The method failed to execute after 3 retries..
[ System.ApplicationException: Communication error.
   at Cinchoo.Core.ChoWaitForTest.Program.&lt;Main&gt;b__0() in C:\Personal\Cinchoo.Fr
amwork\Cinchoo.Core.Test\Cinchoo.Core.ChoWaitFor.Test\Program.cs:line 18
   at Cinchoo.Core.ChoWaitFor.WaitFor[TResult](Func`1 func, Int32 timeout, Int32
 maxNoOfRetry, Int32 sleepBetweenRetry) in C:\Personal\Cinchoo.Framwork\Cinchoo.
Framework\Cinchoo.Core\WaitFor\ChoWaitFor.cs:line 148 ]

[ System.ApplicationException: Communication error.
   at Cinchoo.Core.ChoWaitForTest.Program.&lt;Main&gt;b__0() in C:\Personal\Cinchoo.Fr
amwork\Cinchoo.Core.Test\Cinchoo.Core.ChoWaitFor.Test\Program.cs:line 18
   at Cinchoo.Core.ChoWaitFor.WaitFor[TResult](Func`1 func, Int32 timeout, Int32
 maxNoOfRetry, Int32 sleepBetweenRetry) in C:\Personal\Cinchoo.Framwork\Cinchoo.
Framework\Cinchoo.Core\WaitFor\ChoWaitFor.cs:line 148 ]

[ System.ApplicationException: Communication error.
   at Cinchoo.Core.ChoWaitForTest.Program.&lt;Main&gt;b__0() in C:\Personal\Cinchoo.Fr
amwork\Cinchoo.Core.Test\Cinchoo.Core.ChoWaitFor.Test\Program.cs:line 18
   at Cinchoo.Core.ChoWaitFor.WaitFor[TResult](Func`1 func, Int32 timeout, Int32
 maxNoOfRetry, Int32 sleepBetweenRetry) in C:\Personal\Cinchoo.Framwork\Cinchoo.
Framework\Cinchoo.Core\WaitFor\ChoWaitFor.cs:line 148 ]
Press any key to continue . . .

Happy coding!!!