Cancel asynchronous requests with progress reporting without losing session data

 

            UDAParts
            support@udaparts.com
            Created on 11/15/2010

 

 

            

 

 

Introduction

 

SocketPro is written with requests batching, asynchronous and parallel computation in mind. One of many unique features is that you can easily implement cancelable computation with progress reporting without losing session data.

 

This simple sample is used to demonstrate the usage of this feature.

 

It is noted that the sample code for C++, C# and VB.NET is located at the directory of C:\Program Files (x86)\UDAParts\SocketPro\samples\RemoteSum after you install SocketPro package.

 

SocketPro universal interface definition file

 

Here is the content of the uid file named as RemoteSum.uid. The service named as RemSum contains two slow requests having dollar sign ahead, DoSum and RedoSum. The request Pause is a fast request.

 

[ServiceID = 10]

RemSum

{

                                $int DoSum(int start, int end);

                                int Pause();

                                $int RedoSum();

}

 

The request DoSum is designed to sum all of integer numbers between the inputs start and end. Calling the request Pause will stop processing request DoSum or RedoSum and returns the result of sum at current time.

 

Create skeleton codes for both client and server projects

 

            You can follow the video tutorial one to create skeleton codes for both client and server projects by use of the tool uidparser.exe and the above uid file.

 

Manually add one id for reporting progress from server to client

 

            We need to manually add one request id into constants definition file (RemoteSum_i.cs) as the below.

 

            public const short idReportProgress = (idRedoSumRemSum + 1);

 

Analyze one code snippet

           

            The peer socket contains three session integer variables, m_nSum, m_nStart and m_nEnd, to track the current result of sum, the beginning of integer and the end of integer. The most important code snippet is listed as the below.

 

private int Compute()

                {

                                int n;

                                for (n = m_nStart; n <= m_nEnd; ++n)

                                {

                                                m_nSum += n;

                                                System.Threading.Thread.Sleep(100); //simulate slow request

                                                int rtn = SendResult(RemoteSumConst.idReportProgress, n, m_nSum);

                                                if (rtn == CClientPeer.REQUEST_CANCELED || rtn == CClientPeer.SOCKET_NOT_FOUND)

                                                                break;

                                }

                                m_nStart = (n + 1);

                                return m_nSum;

                }

 

            The code is repeatedly pushing a message having a progress position (n) and its result of sum (m_nSum) with id equal to idReportProgress. Also, SocketPro is monitoring the base request Cancel and socket closing event during looping. When a client asks for canceling computation by sending a base request Cancel, the method SendResult will return CClientPeer.REQUEST_CANCELED. If SocketPro detects the socket closed, it will return CClientPeer.SOCKET_NOT_FOUND. SocketPro server will stop pushing message when it detects them or computation is completed.

 

Display computing progress and result of sum

 

            At client side, we use the below code to report progress and computing result.

 

            public void Process(CAsyncResult AsyncResult)

                {

                                switch (AsyncResult.RequestId)

                                {

                                case RemoteSumConst.idPauseRemSum:

                                case RemoteSumConst.idRedoSumRemSum:

                                case RemoteSumConst.idDoSumRemSum:

                                                {

                                                                int rtn = 0;

                                                                AsyncResult.UQueue.Pop(ref rtn);

                                                                txtSum.Text = rtn.ToString();

                                                }

                                                break;

                                case RemoteSumConst.idReportProgress:

                                                {

                                                                int nWhere = 0;

                                                                int nSum = 0;

                                                                AsyncResult.UQueue.Pop(ref nWhere);

                                                                AsyncResult.UQueue.Pop(ref nSum);

                                                                txtSum.Text = "Where = " + nWhere.ToString() + ", Sum = " + nSum.ToString();

                                                }

                                                break;

                                default:

                                                break;

                                }

                }

 

            As you can see, the above code snippet is very simple and highly understandable. We just display results whenever there is a message with id equal to RemoteSumConst.idReportProgress from server side.

 

Cancel executing request

 

            SocketPro implements a base request named as Cancel for canceling one or more executing or queued requests at server side from a client. You can simply use the below code to serve this purpose.

 

            private void btnPause_Click(object sender, EventArgs e)

                {

                                m_cs.BeginBatching();

 

                                 //send a cancel request to a remote server. Here is a big secret from SocketPro!

                                m_cs.Cancel();

 

                                m_ash.SendRequest(RemoteSumConst.idPauseRemSum);

                                m_cs.Commit(true); //make two requests in one shot

                }

 

Test the sample client and server applications

 

            After compiling the sample projects and running your SocketPro server first, you can start the client application as shown in the above. After clicking the button Do Sum, you will see the computing progress and the result of sum. Once you click the button Pause, the computation will stop, and will be restored if you click the button Redo Sum. No matter how many times you start or stop computing, the final sum result is the same.

 

As you can see, this sample demonstrates a simple implementation with the following key features.

 

·         Requests can be canceled easily with SocketPro.

·         Session variables can be kept and restored no matter how you stop and restore server applications.

·         You can easily track the computing progress by keeping on pushing messages from server onto client.

 

Other examples for usage of cancel

 

            This is just a simple example for demonstration purpose only. Actually, you can use this SocketPro feature to complete the following common tasks. This feature has already been extensively used for load balancing in SocketPro.

 

·         Canceling an executing long lasting database command from a client. Many database client APIs like MS SQL server, Oracle and DB2 support cancel executing command from a new thread.

·         Canceling fetching a large set of records from a server to a client.

·         Canceling downloading a large file from a server.

Further readings