In my previous post I discussed a bit about CallContext and how it can be used with WCF. In this post I will attempt to describe an issue I encountered and a possible workaround.
Issue
The CallContext looks pretty convincing when it comes to storing "state" of a WCF service on a per-request basis. This "state" flows through the local call context and very beneficial for async-await methods.
What I did notice is that under load (I mean with 10 requests per seconds), the content in the CallContext is shared. Which is pretty Bad.
Tool
In order to reproduce this issue, we need to use JMeter (or any load testing framework). JMeter is a tool that is used for load testing a web application.The documentation of JMeter may be bit scratchy, but is it worth the effort.
Reproducing the issue
We will need to add the following code to a WCF service. (Code is checked in here, and I will extract parts to explain the issue.)
Ideally we should never see "(GetPaymentDetails) CallContext already has..." message as this will shown only when there is something already in the CallContext.
Reflecting on the results
Normally Threads in the .NET framework is polled. This would mean same Thread will be used to execute multiple requests. After a request is complete, the Thread returns to the Thread pool.
So what seem to be happening is that the CallContext state is returned with the Thread to the Thread pool. When the same Thread is reused to process another request, it is quite possible that the state is still preserved in the Thread itself.
This could be a bug or expected behaviour of the CallContext.
What if we reset the CallContext at the end of the request? The CallContext reset is through a call to CallContext.Clear method. This may work. However in the scenario where multiple async-await method are used, we cannot be 100% sure that context is cleared across all the the Threads used to process the request.
Normally in .NET 4.5 CallContext uses "copy-on-write" behaviour. (more on this is here.) So although we reset in one Thread it is not propagated across all the Thread that we used to process a particular request. Therefore resetting it "at the end" of a request is not quite correct.
Workaround
The workaround is to introduce a "MessageInspector". At the beginning of the request we can reset the CallContext with a call to CallContext.Clear. This way we make sure the CallContext is cleared for the request.
Given the shortcomings of CallContext, I am not sure whether there is any other solution that may work consistently .
Labels
Android
Android part 1
Architecture
Article
ASP.NET
ASP.NET MVC
Async
AWS
AWS CLI
Baby
base image
Basic Concepts
Bridge pattern
C#
CallContext
Castle Windsor
CloudFormation
Command line
Continuous Integration
Coursera
Create IAM policy
Custom AMI
DaiySelfie
Design patterns
EC2
Encapsulation
Entity Framework
Geolocation
Google App Engine
HTML
HTML5
IAM
IIS
Improvements
Inheritance issues
Instance user data
Ioc
Java
JavaScript
KnockoutJs
Lanching EC2
Learning
Memory
MSBuild
OOP
pair programming
Perfmon
Pluralsight
Principals
Python
SimpleAPI
Sockets
Solutions Architect
SQL Server
SQS
State pattern
TFS 2010
Threading
Type Covariance
Udacity
Unit testing
Visitor pattern
WCF
Web Development
WebApi
Windows VMs
Tuesday, 17 March 2015
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment