I have an async function which will go and do some long running and CPU intensive task. As it is async it doesn't hold up the UI.
Under normal conditions I have no problem with the way it runs. The process is triggered on a button click, but it could be triggered on an API call.
I found that if I hit the button many many times in quick succession, the whole site starts to respond slowly.This is an abusive type of use but nevertheless it has a detrimental impact on performance.
I would like to implement a list in memory of calls to functions by user so that each user would be able to have a single instance the long running function running, but it would not accept any further requests from that user.
Who knows of some clever way of implementing this or has done something like that before. I'm thinking of something like a threadsafe collection you can add tasks to, but if you try to .Add a task that is already running for a certain user / claimsprincipal, then it will fail to add it.
Without diving into the question of whether doing this is the right thing for your specific business situation and architecture, I see your question as basically boiling down to this: How can I ensure that a user can only invoke a particular process one at a time.
You could use a threadsafe collection to hold a flag for each user that indicates whether they are currently running such a process. Use a try{}finally{} block in your async code to manage the value. Set it to true inside the try block and set it to false in the finally. The rest of your long running work comes after you set it to true and before you the finally is executed. sketched out below:
try{
//if thread safe value for this user is already true then exit.
//set thread safe collection value for this user to true
//Do work
}finally{
//set thread safe collection value for this user to false;
}
If it were me, I'd put an object in the collection where the object has one value which was the bool. That way I could use the lock
keyword to hold a lock on the object for that user when I was checking it's value or setting it's value so that I could ensure that no other process changed the value between when I checked it and when I set it.
Hope that helps.