I have a web application that maintains a version flag as a ServletContext.setAttribute('flag', flagValue)
A Filter uses this flagValue in its doFilter method applied to diff servlets.
There is a notification service which toggles the value of the 'flag'.
Now I need to deploy this app in a clustered environment. Given the fact that ServletContext is per JVM, how do I propagate the update received on the notification url across the multiple servers in the cluster?
You can use Dynacaches DistributedMap to share the value across the cluster, then the other servers just need to check for changes when they would be affected by it.
Ended up notifying individual AppServer urls.
Related
I have a .Net core application that consists of some background tasks (hosted services) and WEB APIs (which controls and get statuses of those background tasks). Other applications (e.g. clients) communicate with this service through these WEB API endpoints. We want this service to be highly available i.e. if a service crashes then another instance should start doing the work automatically. Also, the client applications should be able to switch to the next service automatically (clients should call the APIs of the new instance, instead of the old one).
The other important requirement is that the task (computation) this service performed in the background can’t be shared between two instances. We have to make sure only one instance does this task at a given time.
What I have done up to now is, I ran two instances of the same service and use a SQL server-based distributed locking mechanism (SqlDistributedLock) to acquire a lock. If a service could acquire a lock then goes and do the operation while the other node waiting to acquire the lock. If one service crashed the next node could be able to acquire the lock. On the client-side, I used Polly based retry mechanism to switch the calling URL to the next node to find the working node.
But this design has an issue, if the node which acquired the lock loses the connectivity to the SQL server then the second service managed to acquire the lock and started doing the work while the first service is also in the middle of doing the same.
I think I need some sought of leader election (seems done it wrongly), Can anyone help me with a better solution for this kind of a problem?
This problem is not specific to .Net or any other framework. So please make your question more general so as to make it more accessible. Generally the solution to this problem lies in the domain of Enterprise Integration Patterns, so consult the references as the status quo may change.
At first sight and based on my own experience developing distributed systems, I suggest two solutions:
use a load balancer or gateway to distribute requests between your service instances.
use a shared message queue broker to put requests in and let each service instance dequeue a request for processing.
Either is fine and I can use both for my own designs.
I am building a web application that current utilizes two SignalR hubs:
ChatHub - User communication
ControlHub - User manipulates controls and receives responses from server
I want to add a third hub: GuideHub that will be responsible for determining whether or not a user has completed a set of tasks that they are assigned on the website. Technically, this hub will be active whenever ChatHub is active (they share a page element) but they serve thematically different purposes. Generally, users will only be actively communicating across one hub at a time.
I know that premature optimization is usually no good, in this scenario, I need to plan ahead about how I am going to enable these features to scale well. Is this architecture scale-able or should I combine ControlHub and GuideHub to reduce the number of open connections users will have?
2.x support multiple hubs over one connection
http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#multiplehubs
I have a WCF service with ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple). I want to use ThreadStatic variable to srore data.
I start worrying about is it possible two parallel requests for the same or different operationContracts get handled by the same thread serverside, because if this happens my ThreadStatic variable will get overriden.(I.e. something like the thread changing between HttpHandlers and HttpModules in ASP.NET)
I made a spike service with the same ServiceBehaviour and maxConcurrentCalls="2". After that a wcf client called the service with 50 parallel requests and my worry did not occur. However this is not a 100% proof.
Thank in advance!
Irrespective of the ConcurrencyMode, a ThreadStatic value will persist when your request terminates and the thread is returned to the thread pool. The same thread can be reused for a subsequent request, which will therefore be able to see your ThreadStatic value.
Obviously this won't be true for two concurrent requests, because by definition they will be executed on different threads.
From comments:
Also by definition MSDN says: 'The service instance is multi-threaded. No synchronization guarantees are made. Because other threads can change your service object at any time, you must handle synchronization and state consistency at all times.' So it is not so obvious:)
This means that a single instance of your service class can be accessed concurrently by multiple requests. So you would need to handle synchronization for any accesses to instance members of the service class.
However ThreadStatic members are by definition only used by one thread (and hence one request) at a time, so don't need synchronization.
The direct answer to your question is Joe's answer.
However you mention in the comments you are using an ambient design pattern. That pattern is already implemented in WCF as the OperationContext and is specifically designed to be extensible. I highly recommend using OperationContext over any custom thread storage.
See Where to store data for current WCF call? Is ThreadStatic safe?
I wanted to add to Joe's answer here because I would recommend that you use some sort of correlation for your requests if you're needing to store state. The threading model will become very convoluted and unreliable in production.
Further, now imagine you have two IIS servers hosting this service and a hardware or software load balancer forward facing so that you can consume it. To ensure that the correct state is gathered you'll need correlation because you never know which server the service will be started on. In the post below I mocked up a simplified version of how that might work. One thing to keep in mind is that the SessionState would need to be kept in a shared location to all instances of the service, an AppFabric Cache server for example.
Global Variable between two WCF Methods
I was reading a book on Java Servlets where I came across HTTPSessionActivationListener. It was specified that in a clustered environment , there can be only one HTTPSession object containing a specific session id. Assume there are 2 nodes A and B in a cluster -
first request goes to node A. Here a HTTPSession S1 is created along with session attributes and response goes back to the client.
Same client sends the subsequent request. This request goes to node B. Now the session object S1 is moved from node A to node B (activated in Node B and passivated in node A).
In this case should the session object along with the attributes be serializable? What happens if it is not serializable?
In order to count the number of active sessions , should the sessions in both nodes be added up to get the actual value? How is this usually done?
Also I guess ServletContext is unique for each JVM. Are the attributes set as part of servletcontext copied to servlet context in all nodes of the cluster?
Usually I've seen people use sticky sessions (provided usually by the load balancer, for example ec2 ELB has this feature: http://shlomoswidler.com/2010/04/elastic-load-balancing-with-sticky-sessions.html), OR the session data is stored in a shared repository, such as a database or NoSQL store.
Spring session seems to be offering a capability called 'Clustered Sessions' and it also has feature to offload the session to a RedIs or GemFire caching solution.
Reference: http://projects.spring.io/spring-session/
Using a caching solution like Infinispan, hazelcast or redis would be the way to go if you want sessions to survive server failure. Application servers provide these function integrated now a days. You can just enable them from admin interface for web/ejb/jms persistance. If you are storing something into session in your code, you can use JCache API to store them on the underlying cache. JCache provides a product independent caching API, makes you code portable across caching solutions.
I want to run a "background job" in my ASP.NET application (periodically, as separate thread). And I need host name (DNS name or IP) to do my tasks. The problem is that the HttpContext.Current may be not available here (it's NULL).
Is there any way to get a host name in not using HttpContext.Current.Request.Url.Host.
When the host name is available in HttpContext.Request.Url.Host, it is a result of the host name being part of the request sent by the client. As an example, take a request to this page:
GET /questions/2164261/get-host-name-without-using-httprequest HTTP/1.1
Host: stackoverflow.com
...
When running in a background thread, no request context is available, and there really is no concept of a host name at all. Your only alternative is to store the hostname within the code or in configuration.
Slightly off topic: Running scheduled tasks within a web application is asking for trouble, and spawning threads only deals with a few of them. If at all possible, consider running your scheduled jobs from a Windows service, possibly built using a framework like NCron.
probably you can add a class variable in your thread class, and set this variable with request.url.host before you run the thread class.
this method can also apply to the session object.
Keep in mind that it's a bad idea to initiate that "background job" from a web application if you need that background process to run 24/7 independently. Even if you start it in a new thread. Your web app may have no requests for some time. In this case the run time will shut down the process and all its "child" threads. For continuous running you need to run it as a Windows service. Otherwise, the Darren is right, use the System.Net.Dns.GetHostName().
I'm using the same approach as you for scheduling regular tasks and the way I worked around this is to store the machine name for later use when the application gets any kind of web request.
It's a rather dirty hack, but the only way to do this unless you want to hard-code it or retrieve it from an external configuration file, which was too dangerous (unreliable) for my purposes.