Detecting Client Connection in WCF Long Running Service (Heartbeat Implementation) z
Introduction
Hello everyone! This is my first blog on WCF and I hope that you like it.
Today, I will talk about how to implement heart beat mechanism in WCF, so that whenever client is not alive, our WCF service 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 no easy way to detect client has been closed or client is abruptly killed somehow.
Now, I am presenting one scenario and the problem in 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 WCF service gets killed.
Problem
Then the WCF service will continue to run till the whole method completes its execution, it means full 1 hour. WCF service does not have mechanism to stop its execution when client is no longer active or alive. It will waste huge server resource and will keep server busy in case resource is scarce on server side.
Solution
Suppose we have a method called “DoWork” that will take 1 hour to complete its execution.
[ServiceContract]
public interface ILongRunningService
{
[OperationContract]
Output DoWork();
}
Now to resolve the problem statement, we have to refactor this method into the below code snippet.
[ServiceContract]
public interface ILongRunningServiceV2
{
[OperationContract]
void StartDoWork(); [OperationContract]
Status ContinueWorkAndGetStatusFromServer(); [OperationContract]
Output GetFinalDoWork();
}
Now the method “DoWork” is divided into two parts, one is “StartDoWork” and the second is “GetFinalDoWork”.
The client will now call the first method “StartDoWork” and return immediately, “StartDoWork” will spawn a thread for its execution.
Then client will call “ContinueWorkAndGetStatusFromServer” continuously in while loop with wait (Thread.Sleep) of 1 second. This is required because it will keep the server informed that client is still connected to WCF Service and “DoWork” method execution should not stop. In case client does not call this method “ContinueWorkAndGetStatusFromServer”, then service after few elapsed seconds will stop the execution of “DoWork”.
In case client keeps calling this method and method “DoWork” completes its execution, then the client will 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”.
public class LongRunningService : ILongRunningService
{
public Output DoWork()
{
var builder = new StringBuilder();
for (int count = 0; count < 10; count++)
{
builder.Append("Count: " + count);
Thread.Sleep(1000);
}
return new Output(builder.ToString());
}
}
Now, we have created one SessionManger class for managing the session of active client.
Whenever any client connects to our service, it will go through the SessionManager class which will maintain the object of ServiceProvider.
ServiceProvider is our new refactored implementation of method “DoWork”.
Copy Codepublic class ServiceProvider
{
private Output _resourceOutput;
private readonly Status _status;
private volatile bool _shouldDisconnect = false;
private Timer _timer;
private DateTime _clientDateTime; public ServiceProvider()
{
this._status = new Status()
{
Message = "Initialized",
OperationStatus = OperationStatus.None
};
} public void StartDoWork()
{
TimerCallback timerCallback = StopActivity;
_clientDateTime = DateTime.Now;
_timer = new Timer(timerCallback, null, 2000, 2000);
Task.Factory.StartNew(this.RunActivity);
} public Status ContinueProcessingAndGetStatus()
{
_clientDateTime = DateTime.Now;
return this._status;
} public Output GetFinalDoWork()
{
if (this._status.OperationStatus == OperationStatus.Ready)
{
return this._resourceOutput;
}
else
{
throw new Exception("Exception");
}
} private void 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.
Copy Codepublic static class SessionManager<TSessionHandler> where TSessionHandler
: new()
{
private static readonly 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 client code, the method “WithNormalService” is an old way of calling and method “WithVersion2Service” is a new way of calling service.
Copy Codestatic void 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 (!serviceMsg.Equals(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 was the flow of calling between client and service.
Client ---> DoWork
Now after the implementation of Heartbeat in WCF Service, this is the new way of calling WCF Service.
Client ---> StartDoWork
Client ---> ContinueWorkAndGetStatusFromServer in a while loop till it get Operation Status Ready, then it will call GetFinalDoWork.
Client ---> GetFinalDoWork
Point of Interest
One improvement point in this code is to remove the dead client references from the dictionary in SessionManager class.
Detecting Client Connection in WCF Long Running Service (Heartbeat Implementation) z的更多相关文章
- wcf和web service的区别
1.WebService:严格来说是行业标准,不是技术,使用XML扩展标记语言来表示数据(这个是夸语言和平台的关键).微软的Web服务实现称为ASP.NET Web Service.它使用Soap简单 ...
- WCF和Web Service的 区(guan)别(xi)
参考文献:http://social.microsoft.com/Forums/zh-CN/c06420d1-69ba-4aa6-abe5-242e3213b68f/wcf-webservice 之前 ...
- ORA-12518,TNS:listener could not hand off client connection
前几天在启动应用的时候,在控制台抛出了此异常信息!很明显是数据库方面的问题,不过具体是什么问题哪?百度了一下,网上关于此问题的信息还是有比较多,从异常的提示中我们也能看到是具体是和客户端的连接相关的问 ...
- 本地运行项目成功 ,但在服务器运行程序就会报Failed to establish a new connection: [Errno -2] Name or service not known
equests.exceptions.ConnectionError: HTTPSConnectionPool(host=): Max retries exceeded with url: /appa ...
- 扩展Wcf call security service, 手动添加 Soap Security Head.
有次我们有个项目需要Call 一个 Java 的 web service, Soap包中需要一个 Security Head <soapenv:Header> <wsse:Secur ...
- Entity Framework + WCF REST JSON Service
利用EF 和WCF 建立一个REST JSON Service. 首先我们要下载一个Visual Studio 的Template 叫 "ADO.NET C# POCO Entity Gen ...
- WCF - Versus Web Service
There are some major differences that exist between WCF and a Web service which are listed below. 这里 ...
- WCF: Retry when service is in fault state.
Service Host: using System; using System.Configuration; using System.ServiceModel; using System.Serv ...
- WCF宿主Window Service Demo
尝试了下将服务寄宿在window 服务上.具体步骤如下 整个解决方案截图 一.创建window 服务 Wcf.WinService namespace Wcf.WinService { public ...
随机推荐
- CSAPP阅读笔记-汇编语言初探(算术和逻辑操作类指令)-来自第三章3.5的笔记-P128-P135
1.算术和逻辑操作类指令分四类:加载有效地址,一元操作,二元操作和移位,如下: 2. leaq指令,类似mov指令,它左侧的数看似是给出一个地址,在内存中从给定的地址取操作数,传给右边的目的地.但其实 ...
- Python时间calender模块介绍
获取某月日历 Calendar模块有很广泛的方法用来处理年历和月历,例如打印某月的月历: #!/usr/bin/python # -*- coding: UTF-8 -*- import calend ...
- selenium+Python(浏览器操作)
1 .浏览器最大化我们知道调用启动的浏览器不是全屏的,这样不会影响脚本的执行,但是有时候会影响我们“观看”脚本的执行. #coding=utf-8 from selenium import webdr ...
- dfs.replication、dfs.replication.min/max及dfs.safemode.threshold.pct
一.参数含义 dfs.replication:设置数据块应该被复制的份数: dfs.replication.min:所规定的数据块副本的最小份数: dfs.replication.max:所规定的数据 ...
- clearfix的用法
如果有一个DIV作为外部容器,内部的DIV如果设置了float样式,则外部的容器DIV因为内部没有 clear,导致不能被撑开.看下面的例子:Div布局如下:Css代码如下:.out{border:1 ...
- java多线程开发之CyclicBarrier,CountDownLatch
最近研究了一个别人的源码,其中用到多个线程并行操作一个文件,并且在所有线程全部结束后才进行主线程后面的处理. 其用到java.util.concurrent.CyclicBarrier 这个类. Cy ...
- lua热重载
热重载,就是不重新开unity让代码的变化直接看出来,一般在开发时候使用 lua中通过require导入的文件,最终都存在package.loaded这个table中.require会判断是否文件已经 ...
- out参数
out参数: 参数在方法的内部必须为其赋值:可以同时返回不同类型的值: 在Main方法里定义,在方法里赋值: 输 ...
- aspose.word 读取word段落内容
注:转载请标明文章原始出处及作者信息 aspose.word 插件下载 链接: http://pan.baidu.com/s/1qXIgOXY 密码: wsj2 使用原因:无需安装office,无兼容 ...
- Oracle 数据库字典 sys.col$ 表中关于type#的解释
sys.col$ 表是oracle基础数据字典表中的列表,表中描述了数据库中各列信息,其中type#是列的数据类型.以下表格说明了各个数值的含义,以供参考. 值 说明 1 如果列 charsetfor ...