Introduction
Hello everyone! This is the My first blog on WCF and I hope it.
Today, I'll talk about how to implement heart beat mechanism in WCF, so, whenever client is not alive, our WCF servi Ce detects it and kills its long running process and saves the server resources for other clients.
Background
Basic knowledge of WCF is required.
Using the Code
IMHO, I think there is the no easy-to-detect client have been closed or client is abruptly killed somehow.
Now, I am presenting one scenario and the problem with it and at last, the solution for it.
Scenario
Suppose there is one service which takes lots of time to complete, say 1 hour. And in-between, the client of the WCF service gets killed.
Problem
Then the WCF service would continue to run till the whole method completes their execution, it means full 1 hour. WCF service does not has mechanism to stop its execution when the client is no longer active or alive. It would waste huge server resource and would keep server busy in case resource was scarce on server side.
Solution
Suppose we have a method called "," that would take the 1 hour to complete its DoWork
execution.
Hide Copy Code
Interface Ilongrunningservice { [OperationContract] Output DoWork (); }
Now to resolve the problem statement, we had to refactor this method into the below code snippet.
Hide Copy Code
[ServiceContract] interface ILongRunningServiceV2 { [operationcontract] void Startdowork (); [OperationContract] Status continueworkandgetstatusfromserver (); [OperationContract] Output getfinaldowork (); }
Now the method ' DoWork
is divided to ' parts, one is ' "and the second is" StartDoWork
GetFinalDoWork
".
The client would now call the first method " StartDoWork
and return immediately," StartDoWork
"would spawn a thread for its execution.
Then client would call the " ContinueWorkAndGetStatusFromServer
continuously in while
loop with wait
( Thread.Sleep
) of 1 second. This is required because it would keep the server informed that client was still connected to WCF Service and " DoWork
" method Execution should not stop. In case client does the " ContinueWorkAndGetStatusFromServer
" and then service after few elapsed seconds would stop the execution of " DoWork
”.
In case client keeps calling this method and method " DoWork
completes it execution, then the client would call" GetFinalDoWork
"to Fetch the result from the service.
This implementation is also called Heart beat implementation.
Now you can see the code snippet below and download the source code.
And this is the original implementation of method " DoWork
".
Hide Copy Code
Class Longrunningservice:ilongrunningservice {public Output DoWork () { new StringBuilder ( ); For (Ten; count++) {Builder. Append ("count:" + count); Thread.Sleep (Thenew Output (builder. ToString ()); } }
Now, we had created one SessionManger
class for managing the session of active client.
Whenever any client connects to our service, it'll go through the SessionManager
class which would maintain the object of ServiceProvider
.
ServiceProvider
Is our new refactored implementation of method " DoWork
".
Hide Shrink Copy Code
PublicClass ServiceProvider {Private Output _resourceoutput;PrivateReadOnly Status _status;PrivateVolatileBOOL _shoulddisconnect =FalsePrivate Timer _timer;Private DateTime _clientdatetime;Public serviceprovider () {This._status =New Status () {Message ="Initialized ", operationstatus = Operationstatus.none}; }Publicvoid Startdowork () {TimerCallback TimerCallback = stopactivity; _clientdatetime = DateTime.Now; _timer =New Timer (TimerCallback,Null2000,2000); Task.Factory.StartNew (This. runactivity); }Public Status Continueprocessingandgetstatus () {_clientdatetime = DateTime.Now;ReturnThis._status; }Public Output getfinaldowork () {if (This._status. Operationstatus = = Operationstatus.ready) {ReturnThis._resourceoutput; }else {ThrowNew Exception ("Exception "); } }Privatevoid Runactivity () {This._status. Operationstatus = operationstatus.working;var builder =New StringBuilder ();for (int count =0; Count <10; count++) {if (_shoulddisconnect)break; builder. Append ( "count:" + Count); Thread.Sleep (1000); Debug.WriteLine (count); this._status. Message = count. ToString (); } this._status. Operationstatus = Operationstatus.ready; _resourceoutput = new Output (builder. ToString ()); } private void stopactivity ( Object state) {TimeSpan span = DateTime.Now-_clientdatetime; if (span > new TimeSpan (0, 0, 7) {this._timer. Dispose (); _shoulddisconnect = true;} }
This is a SessionManager
class.
Hide Shrink Copy Code
PublicStaticClass sessionmanager<tsessionhandler>where Tsessionhandler:New () {PrivateStaticReadOnly concurrentdictionary<string, tsessionhandler> sessionhandlers =new concurrentdictionary<string, tsessionhandler> (); private static readonly object syncobject = new object (); public static Tsessionhandler getsession () { var sessionId = OperationContext.Current.SessionId; if (Sessionhandlers.containskey (sessionId)) {return Sessionhandlers[sessionid]; } else {lock (syncobject) {Tsessionhandler handler = new Tsessionhandler (); Sessionhandlers.tryadd (sessionId, handler); return handler;} } }}
This is the client code, the method "was an old by- WithNormalService
calling and method" WithVersion2Service
"is a new-to-a-calling service.
Hide Shrink Copy Code
Staticvoid Withnormalservice () {longrunningserviceclient client =New Longrunningserviceclient ();var result = client. DoWork (); Console.WriteLine (Result. Finalvalue); }static void Withversion2service () { Longrunningservicev2client client = new longrunningservicev2client (), client. Startdowork (); string servicemsg = string. Empty; Status Status = Client. Continueworkandgetstatusfromserver (); Console.WriteLine (status. Operationstatus); do {if (!string. IsNullOrEmpty (status. Message) {if (status. Message) {servicemsg = status. Message; Console.Out.WriteLine (status. Message); }} thread.sleep (500); status = Client. Continueworkandgetstatusfromserver (); } while (status. Operationstatus! = Operationstatus.ready); Servicereferencev2.output image = Client. Getfinaldowork (); Console.WriteLine (image. Finalvalue); }
Earlier, this is the flow of calling between client and service.
Client--->DoWork
Now after the implementation of Heartbeat in WCF service, this is the new from calling WCF service.
Client--->StartDoWork
Client---> ContinueWorkAndGetStatusFromServer
in a while
loop till it get Operation Status ready and then it'll call GetFinalDoWork
.
Client--->GetFinalDoWork
Point of Interest
One improvement point in this code was to remove the dead client references from the dictionary in SessionManager
class.
Detecting Client Connection in WCF Long Running Service (Heartbeat implementation) Z