Client server architecture question - c#

I am working on a client server system, and am running into issues where multiple clients are executing an action at the same time. We are able to solve this by locking on the critical section of code, which ensures that the first client will complete the action before the second client enters the code block. My question is this: our server is also clustered, so multiple instances of the server itself can exist, which recreates the same problem as before. How could we solve this problem?
Thanks!
To expand on the problem: The first user is checking if an action is valid and getting a yes response. The second user is checking if an action is valid and also getting a yes response before the first user completes his/her action. But the first user's action should make the second user's action invalid. The problem is that the check occurs nearly simultaneously for each user.

It sounds like you have a bad design. Your service should not maintain state at all, if possible. That way, there would be no shared state to step on.
If you must maintain state, then you must interlock all access to that shared state. You can use the "lock" keyword in C# for this:
private static object _stateLocker = new object();
private static int _someSharedState = 0;
public void SomeAction()
{
lock (_stateLocker)
{
_someSharedState ++;
}
}
public int GetValue()
{
lock (_stateLocker)
{
return _someSharedState; }
}

More detail about your specific problem would be helpful to get a good solution - however, it's sounds like you need some form of interprocess/cross-server locking. There's nothing directly within the .NET framework (or Win32 APIs) to make this easy - you have to roll your own solution, I'm afraid.
You may want to look into some sort of clustered queuing mechanism so that only one process/thread is executing an action. This may or may not be easy in your overall design and the problem you are trying to solve. Alternatively, you could use a central authority (like a database) and a locking structure to determine if a lock for a particular action has already been started. The problem there is it's hard to make such a solution scale well due to the need to constantly interact with the database.
Another option you may have is to allow multiple process to attempt to process the same action simultaneously but to only allow one to complete. This can be tricky to ensure - but it's less expensive (computationally) to perform extra work and throw it away than to constantly check if someone else is already doing the work.

Related

keep track of current context of user action using SignalR for push notification

If you look at StackOverflow (SO) site, while you are looking at a specific thread and there is some update to that thread, SO pushes the notification to you. That means SO is aware of user context/user action (which thread you are currently seeing). I am trying to build something similar in my ASP.NET web API application using SignalR.
In order to implement this similar behavior, I am performing following steps.
Every time user views a thread, I make a get call to an endpoint to return thread information along with that, I am maintaining a dictionary which I update every time, this endpoint is called. In this dictionary I store the context.connectionId as key and threadId as value (keeping threadId as value since multiple users can view the same thread at the same time).
Anytime a change is made to any thread, I ask the dictionary to return me all the connectionId (keys) where value == threadId.
Then I push notification to all the coonectionId's returned in step2.
Questions:
I feel this is overkill and there might be an easier way to do all this. What is the best approach to handle this scenario?
Do you think this approach will scale well and application performance will not be impacted.
Tomorrow if I move to server farm, would this approach will still work ?
There's nothing wrong with this approach. This seems like a fairly straightforward pubsub approach. A user subscribes to a particular thread upon viewing. The server then publishes updates to that thread to the users who have subbed to it. What you outlined for a context dictionary is really the minimum amount of data needed to send targeted updates to users.
Scaling is fine, although I would argue that you should reverse your dictionary for better performance. You should key off the threadId, and keep a list of connectionIds that have subbed to that thread. In doing so, you'd be able to simply add a connectionId to a an existing list when a new user is viewing a thread. You minimize the amount of data you need to keep in memory. As it stands now, you have to loop over every connectionId to figure out what they're looking at and aggregate that into a single list, so you might as well just reverse it and store the list itself.
It would work so long as each server in the farm handles their own list of connectionId/threadId maps. If each server can respond to a change in the thread independently, then a farm setup should be fine.

Do I need a ConcurrentDictionary? Will regular Dictionary do?

I currently am using a ConcurrentDictionary to hold a collection of login names that have authenticated with my API. I do this to prevent duplicate logins from other web clients (a requirement of the system architecture). If a user authenticates with a login that is already "logged in" they are given a choice ...
Continue and the previous login will be expired
Cancel and the current session will be logged out
I am using a ConcurrentDictionary because it is supposed to be thread safe which is important in an environment where multiple clients are accessing the API.
What I am asking is if the ConcurrentDictionary is needed because I am running into trouble deleting all items in the collection that match a given key. Is a ConcurrentDictionary called for in this case? If not, would a plain Dictionary suffice? If not, and a ConcurrentDictionary is needed is there a method that will remove all entries matching a given key? All I can see is TryRemove() which only seems to remove a single entry.
The direct answer to your question:
Yes, you need a ConcurrentDictionary. You are sharing state across several threads.
Remember, a dictionary has one entry per key. That's the definition of what a Dictionary is, and a ConcurrentDictionary doesn't change that.
A fuller and more complete answer to your requirement is below.
The whole solution is short sighted as you have no connection with the session infrastructure to know when a user's session has timed out and effectively caused them to be logged out. Additionally there is no coordination with other instances of your app if you ever think about deploying to a cloud platform that spins up new instances.
In other words, you are putting yourself in a situation that makes it very difficult to scale your app without breaking this feature.
Probably one of the most robust ways of handling the single session requirement is to use your database:
Have a field that keeps track of the last session ID your user had when logging in.
Add a session listener to clear the field when the session times out
If the session ID is not the same as what's in the field, you know you have a new login attempt.
If you need complete control over the session ID, then supply your own session id manager (may be necessary to include an encoded server ID in it).
You'll find that the requirement is much more involved than it sounds on the surface. You can't think like a desktop application in the web space--which is precisely where this requirement even comes from.

Handling limitations in multithreaded server

In my client-server architecture I have few API functions which usage need to be limited.
Server is written in .net C# and it is running on IIS.
Until now I didn't need to perform any synchronization. Code was written in a way that even if client would send same request multiple times (e.g. create sth request) one call will end with success and all others with error (because of server code + db structure).
What is the best way to perform such limitations? For example I want no more that 1 call of API method: foo() per user per minute.
I thought about some SynchronizationTable which would have just one column unique_text and before computing foo() call I'll write something like foo{userId}{date}{HH:mm} to this table. If call end with success I know that there wasn't foo call from that user in current minute.
I think there is much better way, probably in server code, without using db for that. Of course, there could be thousands of users calling foo.
To clarify what I need: I think it could be some light DictionaryMutex.
For example:
private static DictionaryMutex FooLock = new DictionaryMutex();
FooLock.lock(User.GUID);
try
{
...
}
finally
{
FooLock.unlock(User.GUID);
}
EDIT:
Solution in which one user cannot call foo twice at the same time is also sufficient for me. By "at the same time" I mean that server started to handle second call before returning result for first call.
Note, that keeping this state in memory in an IIS worker process opens the possibility to lose all this data at any instant in time. Worker processes can restart for any number of reasons.
Also, you probably want to have two web servers for high availability. Keeping the state inside of worker processes makes the application no longer clustering-ready. This is often a no-go.
Web apps really should be stateless. Many reasons for that. If you can help it, don't manage your own data structures like suggested in the question and comments.
Depending on how big the call volume is, I'd consider these options:
SQL Server. Your queries are extremely simple and easy to optimize for. Expect 1000s of such queries per seconds per CPU core. This can bear a lot of load. You can use a SQL Express for free.
A specialized store like Redis. Stack Overflow is using Redis as a persistent, clustering-enabled cache. A good idea.
A distributed cache, like Microsoft Velocity. Or others.
This storage problem is rather easy because it fits a key/value store model well. And the data is near worthless so you don't even need to backup.
I think you're overestimating how costly this rate limitation will be. Your web-service is probably doing a lot more costly things than a single UPDATE by primary key to a simple table.

Does a concurrect exception happen to both user

if a user edits a data record and the same time another user edits the same record too and both save.
1.) Will the concurrency exception ALWAYS happen only for one user?
Actually its logical that the first wins but who is the first in a technical aspect... Is it possible both user get this kind of exception?
2.)The one who was too late and getting now the concurrent exception I guess he can access the
new updated data record from the other user yes?
In Read committed default Isolation level of sql server:
If concurrent request to accesss a object is come then sql server creates the queue for them and process them one by one. Second user will wait for a predefined time for user 1 to complete the task and throw the error if unable to complete the task in that time frame. This time frame is configurable in sql server and in ADO.net.
It all depends on isloation level defined in sql server whether you want concurrent access or not.
Read more about ISOLATION Level in DB
1) I think so yes. One will always be earlier than the other; there is no other way around it. So one update will work as normal, the other will throw the concurrency exception.
This might depend on the data access method you are using, there might be systems that can handle such situations more elegantly. But I doubt there are systems that will give both users the same exception without you building that behaviour on purpose.
As Adam Houldsworth says: this could also depend on the way you code it yourself. You could check for multiple users beginning to edit the same record, and then throw the exception to both. But I do not believe that is what you are actually asking. If so; I misunderstood.
2) Of course this is possible, but this is up to you to build in your application. Just catch the concurrency exception and refresh whatever edit form user B was trying to update. He/she can then try again. Generally speaking obviously; I do not know the specifics of your situation.

WCF service with XML based storage. Concurrency issues?

I programmed a simple WCF service that stores messages sent by users and sends these messages to the intended user when asked for. For now, the persistence is implemented by creating username.xml files with the following structure:
<messages recipient="username">
<message sender="otheruser">
...
</message
</messages>
It is possible for more than one user to send a message to the same recipient at the same time, possibly causing the xml file to be updated concurrently. The WCF service is currently implemented with basicHttp binding, without any provisions for concurrent access.
What concurrency risks are there? How should I deal with them? A ReadWrite lock on the xml file being accessed?
Currently the service runs with 5 users at the most, this may grow up to 50, but no more.
EDIT:
As stated above the client will instantiate a new service class with every call it makes. (InstanceContext is PerCall, ConcurrencyMode irrelevant) This is inherent to the use of basicHttpBinding with default settings on the service.
The code below:
public class SomeWCFService:ISomeServiceContract
{
ClassThatTriesToHoldSomeInfo useless;
public SomeWCFService()
{
useless=new ClassThatTriesToHoldSomeInfo();
}
#region Implementation of ISomeServiceContract
public void IncrementUseless()
{
useless.Counter++;
}
#endregion
}
behaves is if it were written:
public class SomeWCFService:ISomeServiceContract
{
ClassThatTriesToHoldSomeInfo useless;
public SomeWCFService()
{}
#region Implementation of ISomeServiceContract
public void IncrementUseless()
{
useless=new ClassThatTriesToHoldSomeInfo();
useless.Counter++;
}
#endregion
}
So concurrency is never an issue until you try to access some externally stored data as in a database or in a file.
The downside is that you cannot store any data between method calls of the service unless you store it externally.
If your WCF service is a singleton service and guaranteed to be that way, then you don't need to do anything. Since WCF will allow only one request at a time to be processed, concurrent access to the username files is not an issue unless the operation that serves that request spawns multiple threads that access the same file. However, as you can imagine, a singleton service is not very scalable and not something you want in your case I assume.
If your WCF service is not a singleton, then concurrent access to the same user file is a very realistic scenario and you must definitely address it. Multiple instances of your service may concurrently attempt to access the same file to update it and you will get a 'can not access file because it is being used by another process' exception or something like that. So this means that you need to synchronize access to user files. You can use a monitor (lock), ReaderWriterLockSlim, etc. However, you want this lock to operate on per file basis. You don't want to lock the updates on other files out when an update on a different file is going on. So you will need to maintain a lock object per file and lock on that object e.g.
//when a new userfile is added, create a new sync object
fileLockDictionary.Add("user1file.xml",new object());
//when updating a file
lock(fileLockDictionary["user1file.xml"])
{
//update file.
}
Note that that dictionary is also a shared resource that will require synchronized access.
Now, dealing with concurrency and ensuring synchronized access to shared resources at the appropriate granularity is very hard not only in terms of coming up with the right solution but also in terms of debugging and maintaining that solution. Debugging a multi-threaded application is not fun and hard to reproduce problems. Sometimes you don't have an option but sometimes you do. So, Is there any particular reason why you're not using or considering a database based solution? Database will handle concurrency for you. You don't need to do anything. If you are worried about the cost of purchasing a database, there are very good proven open source databases out there such as MySQL and PostgreSQL that won't cost you anything.
Another problem with the xml file based approach is that updating them will be costly. You will be loading the xml from a user file in memory, create a message element, and save it back to file. As that xml grows, that process will take longer, require more memory, etc. It will also hurt your scalibility because the update process will hold onto that lock longer. Plus, I/O is expensive. There are also benefits that come with a database based solution: transactions, backups, being able to easily query your data, replication, mirroring, etc.
I don't know your requirements and constraints but I do think that file-based solution will be problematic going forward.
You need to read the file before adding to it and writing to disk, so you do have a (fairly small) risk of attempting two overlapping operations - the second operation reads from disk before the first operation has written to disk, and the first message will be overwritten when the second message is committed.
A simple answer might be to queue your messages to ensure that they are processed serially. When the messages are received by your service, just dump the contents into an MSMQ queue. Have another single-threaded process which reads from the queue and writes the appropriate changes to the xml file. That way you can ensure you only write one file at a time and resolve any concurrency issues.
The basic problem is when you access a global resource (like a static variable, or a file on the filesystem) you need to make sure you lock that resource or serialize access to it somehow.
My suggestion here (if you want to just get it done quick without using a database or anything, which would be better) would be to insert your messages into a Queue structure in memory from your service code.
public MyService : IMyService
{
public static Queue queue = new Queue();
public void SendMessage(string from, string to, string message)
{
Queue syncQueue = Queue.Synchronized(queue);
syncQueue.Enqueue(new Message(from, to, message));
}
}
Then somewhere else in your app you can create a background thread that reads from that queue and writes to the filesystem one update at a time.
void Main()
{
Timer timer = new Timer();
timer.Tick += (o, e)
{
Queue syncQueue = Queue.Synchronized(MyService.queue);
while(syncQueue.Count > 0)
{
Message message = syncQueue.Dequeue() as Message;
WriteMessageToXMLFile(message);
}
timer.Start();
};
timer.Start();
//Or whatever you do here
StartupService();
}
It's not pretty (and I'm not 100% sure it compiles) but it should work. It sort of follows the "get it done with the tools I have, not the tools I want" kind of approach I think you are looking for.
The clients are also off the line as soon as possible, rather than waiting for the file to be written to the filesystem before they disconnect. This can also be bad... clients might not know their message didn't get delivered should your app go down after they disconnect and the background thread hasn't written their message yet.
Other approaches on here are just as valid... I wanted to post the serialization approach, rather than the locking approach others have suggested.
HTH,
Anderson
Well, it just so happens that I've done something almost exactly the same, except that it wasn't actually messages...
Here's how I'd handle it.
Your service itself talks to a central object (or objects), which can dispatch message requests based on the sender.
The object relating to each sender maintains an internal lock while updating anything. When it gets a new request for a modification, it then can read from disk (if necessary), update the data, and write to disk (if necessary).
Because different updates will be happening on different threads, the internal lock will be serialized. Just be sure to release the lock if you call any 'external' objects to avoid deadlock scenarios.
If I/O becomes a bottleneck, you can look at different strategies involving putting messages in one file, separate files, not immediately writing them to disk, etc. In fact, I'd think about storing the messages for each user in a separate folder for exactly that reason.
The biggest point is, that each service instance acts as, essentially, an adapter to the central class, and that only one instance of one class will ever be responsible for reading/writing messages for a given recipient. Other classes may request a read/write, but they do not actually perform it (or even know how it's performed). This also means that their code is going to look like 'AddMessage(message)', not 'SaveMessages(GetMessages.Add(message))'.
That said, using a database is a very good suggestion, and will likely save you a lot of headaches.

Categories