Running slow server procedures - marcos8154/SocketAppServer GitHub Wiki

Some applications are by design, long and time consuming procedures where it is not possible to return an immediate response. To assist in this scenario, the framework provides sophisticated thread control so you can implement your slow code without affecting client response.

Rather, we need to describe a hypothetical scenario where this can be applied.

A purchase order processor

Let's illustrate with a hypothetical purchase processing task, where it takes several steps and checks before ordering, such as access to external services, various data calculations, and the like.

In this situation, the client sends a request to process the request, in which case the server will respond with a status similar to the "Accepted" HTTP world.

By the time the server receives the request to close the request, it will start a new process or thread to perform the lengthy procedure, and at the same time respond to the client that just "accepted" the request.

The server will also make certain Actions available to query the status or progress of the order, which the client will periodically query.

Given the illustration, let's go to the code!

The AsyncTask Class

The AsyncTask class, located in the "MobileAppServer.ServerObjects" namespace, is responsible for executing Threads in a sophisticated, tightly typed, step-by-step manner.

This class is strongly typed, having 3 types in its definition:

   //AsyncTask definition
   public abstract class AsyncTask<TParams, TProgress, TReturn>
  • TParams: This type will define the parameter object that will be injected into the Thread.
  • TProgress: This type will set the sent object as progress, when the Thread makes execution progress available.
  • TReturn: This type will define the thread's return object as soon as it is terminated.

Anatomy of an AsyncTask

    public class MySimpleTask : AsyncTask<string, string, string>
    {
        public override string DoInBackGround(string param)
        {
            //execute slow procedures here

            return "return of task";
        }

        public override void OnPostExecute(string result)
        {
            //code executed AFTER thread end
        }

        public override void OnPreExecute()
        {
            //code executed BEFORE thread start
        }

        public override void OnProgressUpdate(string progress)
        {
            //Code executed when Thread posts progress
        }
    }

Notice the signature of our class:

public class MySimpleTask : AsyncTask<string, string, string>

Note that we are passing 3 types to AsyncTask as strings We could pass any type, but basically we're saying this:

"This is a thread that takes a string as a parameter, posts progress notifications in string format, and when it finishes processing returns a string"

Keep this in mind ALWAYS

How to post progress

Within the DoInBackground (and ALWAYS IN) method, call the abstract class method "UpdateProgress()" It will request as parameter the same type that was defined as "TProgress" in our class signature

        public override string DoInBackGround(string param)
        {
            //execute slow procedures here

            UpdateProgress("Progress of my Thread!");

            return "return of task";
        }

Never directly call the "OnProgressUpdate()" method. This is wrong and may cause problems with your Thread execution.

   public override void OnProgressUpdate(string progress)
   {
      /*
      * As in the example above, 
      * here will be sent the 
      * string "Progress of my Thread!"
      **/
   }

Canceling Thread Execution

Inside the DoInBackground (and ALWAYS IN) method, invoke the CancelTask() method. It asks for a bool parameter, which determines whether the OnPostExecute() method should be invoked, or ignored.

public override string DoInBackGround(string param)
{
    //execute slow procedures here

    UpdateProgress("Progress of my Thread!");

    if (anyCondition)
        CancelTask(false); //cancel task and not run OnPostExecute()

    return "return of task";
}

Note that by canceling a task, the rest of the process will be taken along and the thread will be destroyed.

Why can't I invoke the OnPreExecute(), OnPostExecute(), OnProgressUpdate() methods directly from within DoInBackground()?

These calls cannot happen this way because inside an AsyncTask, the only method that is actually inserted into the thread is DoInBackground.

The other methods are designed to stay out of the thread, are invoked by the AsyncTask controller.

These calls are synchronized automatically by AsynTask. When you invoke such methods from within DoInBackground, you are nothing but executing the methods INSIDE the Thread, which is wrong, as they are meant to communicate with the outside world.

How to perform our Task

Instantiate your Task class normally. After that, invoke the Execute (TParams) method.

It will request the parameter object as defined in its class signature

public ActionResult ProcessOrder(PurchaseOrder order)
{
    PurchaseProcessTask task = new PurchaseProcessTask();
    task.Execute(order);

    return ActionResult.Json(new OperationResult(true, 600, "Your purchase is accepted"));
}

After that, return a response to the client saying only that you received the request. Nothing more, nothing less.

Also provide an Action so that clients can check the progress of the operation:

public ActionResult GetOrderStatus(Guid orderId)
{
    //Here you will consult the progress of the order
    return ActionResult.Json(....);
}

How will I know about the progress of my Thread?

As you may have understood before, Thread is an isolated box. You cannot see what happens inside. That's why the other AsyncTask methods exist.

Inside, you can write information to a data repository, and Query Actions will check those repositories and return progress to Clients.

This information can be persisted when the OnPreExecute(), OnPostExecute(), and OnProgressUpdate() methods are called.

The sky is the limit. Have a good time!

Bonus: passing more than one parameter to AsyncTask

As we have seen, the AsyncTask class is typed, and one of the types is TParam, which defines the parameter object that will be transferred to DoInBackground.

The problem is that on several occasions we need to pass not only one, but a series or set of several parameters. We can create a DTO class in our project to do this. But AsyncTask already has its own way of handling it.

The TaskParams Class

Modify the definition of your Task in the type where TParam is entered. Set as TaskParams

To retrieve parameter values, use the "Get" methods of the TaskParams class, as shown below:

public class PurchaseProcessTask : AsyncTask<TaskParams, string, string>
{
    public override string DoInBackGround(TaskParams param)
    {
        decimal price = param.GetDecimal("price");
        bool isActive = param.GetBool("isActive");
        string anyOtherParam = param.GetString("other");
        PurchaseOrder order = (PurchaseOrder)param.GetValue("purchaseObj");


        UpdateProgress("Progress of my Thread!");
        return "return of task";
    }
.....

To transfer the parameters to AsyncTask, do as the example below in call

PurchaseProcessTask task = new PurchaseProcessTask();
task.Execute(TaskParams.Create()
    .Set("price", 14.50m)
    .Set("isActive", true)
    .Set("other", "Any other param string")
    .Set("order", order));