I'm calling a 3rd party API that uses OAuth for authentication, and I'm wondering how to make this threadsafe:
var token = _tokenService.GetCurrentToken(); // eg token could be "ABCDEF"
var newToken = oauth.RenewAccessToken(token); // eg newToken could be "123456"
_tokenService.UpdateCurrentToken(newToken); // save newToken to the database
What this does is to use the previous token every time RenewAccessToken() is called. But there is a problem if two users initiate this at the same time (two different threads will run the code at the same time), and we end up with that code executed in this order:
[Thread 1] var token = _tokenService.GetCurrentToken(); // returns "ABCDEF"
[Thread 2] var token = _tokenService.GetCurrentToken(); // returns "ABCDEF"
[Thread 1] var newToken = oauth.RenewAccessToken("ABCDEF"); // returns "123456"
[Thread 2] var newToken = oauth.RenewAccessToken("ABCDEF");
// throws an invalid token exception
What has happened is that in thread 2, it should actually be calling oauth.RenewAccessToken("123456"); (because that is the latest token value. But the latest token hasnt even been saved to the database yet, so thread 2 always has the wrong value for current token.
What can I do to fix this?
Edit: It has been suggested to use a lock like this:
private object tokenLock = new object();
lock(tokenLock)
{
var token = _tokenService.GetCurrentToken();
var newToken = oauth.RenewAccessToken(token);
_tokenService.UpdateCurrentToken(newToken);
}
Edit 2: The lock didn't actually work anyway, this is from my logs:
[43 22:38:26:9963] Renewing now using token JHCBTW1ZI96FF
[36 22:38:26:9963] Renewing now using token JHCBTW1ZI96FF
[36 22:38:29:1790] OAuthException exception
The first number is the thread id and the second is a timestamp. Both threads executed at the exact same time down to the milliseconds. I don't know why the lock failed to stop thread 36 until after thread 43 had finished.
Edit 3: And again, this time after changing the object tokenLock to be a class variable instead of a local variable, the lock did not work.
[25 10:53:58:3870] Renewing now using token N95984XVORY
[9 10:53:58:3948] Renewing now using token N95984XVORY
[9 10:54:55:7981] OAuthException exception
EDIT
Given that this is an ASP.NET application, the easy route (a Monitor lock using a lock { } block) is not suitable. You'll need to use a named Mutex in order to solve this problem.
Given your example code, something along these lines would work:
using(var m = new Mutex("OAuthToken"))
{
m.WaitOne();
try
{
var token = _tokenService.GetCurrentToken();
var newToken = oauth.RenewAccessToken(token);
_tokenService.UpdateCurrentToken(newToken);
}
finally
{
m.ReleaseMutex();
}
}
Note the finally clause; it's very important that you release the mutex. Because it's a system-wide object, its state will persist beyond your application. If you were to encounter an exception in your OAuth code above, you would not be able to reenter the code until the system was restarted.
Also, if you have some sort of durable identifier for sessions that use the same OAuth token (something that won't get changed as a result of this process), you could potentially use that token as the mutex name instead of "OAuth" as I have above. This would make the synchronization specific to a given token, so you would not have to worry about operations having to wait on unrelated tokens being renewed. This should offset the increase in cost of a mutex over a Monitor lock.
For the sake of helping others who might find this question, I've left my original answer below:
Original Answer
You just need a simple lock around your operation.
Create an instance (or static, if these functions are static) variable of type object:
private object tokenLock = new object();
In your code, enclose the steps that need to be atomic within a lock(tokenLock) block:
lock(tokenLock)
{
var token = _tokenService.GetCurrentToken();
var newToken = oauth.RenewAccessToken(token);
_tokenService.UpdateCurrentToken(newToken);
}
This will prevent one thread from starting this process while another is executing it.
Related
I have a client to OData system, and it (system) works in following way.
first I have to send a special request to retrieve a token.
then I make my requests, attaching token to each request.
at certain time request may fail, saying that token is outdated. then I should make another special request to get a new token
This is easy when I have only one thread. But I want to have multiple threads doing requests and all sharing the same token. Also if more than one concurrent requests fail with token being invalidated I want to send a special request exactly once and other clients to start using the updated token.
If it matters I am using C#.
Is there a common solution to synchronize such requests?
Without knowing much more about your implementation, one option could be MemoryCache.
Your threads could check the cache for a specific 'tokenkey' and get its value. You can set a expiration in your MemoryCache ahead of a known expiration if you wanted to prevent 401s or other unauthorized results.
Here's an example I use to get/set a new token required for auth header in web api calls:
private string GetNewToken()
{
lock (cacheLock)
{
// no token in cache so go get a new one
var newToken = TokenServiceAgent.GetJwt();
// number of minutes (offset) before JWT expires that will trigger update of cache
var cacheLifetime = 15
CacheItemPolicy cip = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(cacheLifetime.Value))
};
MemoryCache.Default.Set("tokenkey", newToken, cip);
return newToken;
}
}
EDIT: can't get the code block to play nice in the SO editor
I have a network application that uses Lua scripts. Upon starting the application I create a global Lua state and load all script files, that contain various functions, and for every client that connects I create a Lua thread, for that connection.
// On start
var GL = luaL_newstate();
// register functions...
// load scripts...
// On connection
connection.State = lua_newthread(GL);
When a request that uses a script comes in, I get the global function and call it.
var NL = connection.State;
var result = lua_resume(NL, 0);
if (result != 0 && result != LUA_YIELD)
{
// error...
result = 0;
}
if (result == 0)
{
// function returned...
}
Now, some scripts require a response to something from the client, so I yield in those functions, to wait for it. When the response comes in, the script is resumed with lua_resume(NL, 1).
// Lua
text("How are you?")
local response = select("Good", "Bad")
// Host
private int select(IntPtr L)
{
// send response request...
return lua_yield(L, 1);
}
// On response
lua_pushstring(NL, response);
var result = lua_resume(NL, 1);
// ...
My problem is that I need to be able to cancel that yield, and return from the Lua function, without executing any more code in the Lua function, and without adding additional code to the scripts. In other words, I basically want to make the Lua thread throw an exception, get back to the start, and forget it ever executed that function.
Is that possible?
One thing I thought might work, but didn't, was calling lua_error. The result was an SEHException on the lua_error call. I assume because the script isn't currently running, but yielding.
While I didn't find a way to wipe a thread's slate clean (I don't think it's possible), I did find a solution in figuring out how lua_newthread works.
When the thread is created, the reference to it is put on the "global" state's stack, and it doesn't get collected until it's removed from there. All you have to do to clean up the thread is removing it from the stack with lua_remove. This requires you to create new threads regularly, but that's not much of a problem for me.
I'm now keeping track of the created threads and their index on the stack, so I can removed them when I'm done with them for whatever reason (cancel, error, etc). All other indices are updated, as the removal will shift the ones that came after it.
if (sessionOver)
{
lua_remove(GL, thread.StackIndex);
foreach (var t in threads)
{
if (t.StackIndex > thread.StackIndex)
t.StackIndex--;
}
}
I have a service which looks locally in a sql table for a value. If the value does not exist it is doing a remote call. If there is a value returned from the remote call then this value is added to the local sql table.
I have notified Unique Index exceptions in the log file that the string value XXX already exists.
To me that means that the following happened:
Request1_localSqlCheck
Request1_remoteCheck
Request2_localSqlCheck
Request2_remoteCheck
Request1_AddValueLocallyIfRecievedByRemote
Request2_AddValueLocallyIfRecievedByRemote // Same value Added here causes exception.
I want to make all 3 steps atom and lock it:
Lock
{
Request1_localSqlCheck
Request1_remoteCheck
Request1_AddValueLocallyIfRecievedByRemote
}
Will this work putting a lock around these 3 method calls?
You could use a Mutex to block the code execution until the server returns the value.
For example:
private readonly Mutex m = new Mutex();
public int ThreadSafeMethod() {
// you can do this immediately to skip the mutex
if (Request1_localSqlCheck == 1) return 1;
m.WaitOne();
try {
// check again
if (Request1_localSqlCheck == 1) return 1;
Request1_remoteCheck
Request1_AddValueLocallyIfRecievedByRemote
} finally {
m.ReleaseMutex();
}
}
Just to be clear, it can be really problematic if this code is called very frequently because it will slow down all the other thread that will have to wait for the mutex.
IMHO, if the "unique" error is not a big deal, I think you can stick with it; it can be boring, but sometimes is better to try and fail than wait for mutex release and slow down everything.
I have a distributed service that takes anywhere from 10 sec to 10 min to process a message. The service starts on a user's (== browser) request which is received through an API. Due to various limitations, the result of the service has to be returned outside of the initial request (timeouts, dropped client connections ...) Therefore I return a SessionId to the requesting user which can be used to retrieve the result until it expires.
Now it can happen that a user makes multiple consecutive requests for the result while the session is still locked. For example the following code gets hit with the same SessionId within 60 seconds:
var session = await responseQueue.AcceptMessageSessionAsync(sessionId);
var response = await session.ReceiveAsync(TimeSpan.FromSeconds(60));
if (response == null)
{
session.Abort();
return null;
}
await response.AbandonAsync();
What I need is a setup without locking and the ability to read a message multiple times until it expires plus the ability to wait for yet non-existent messages.
Which ServiceBus solution fits that bill?
UPDATE
Here's a dirty solution, still looking for a better way:
MessageSession session = null;
try
{
session = await responseQueue.AcceptMessageSessionAsync(sessionId);
}
catch
{
// ... and client has to try again until the 60 sec lock from other requests is released
}
var response = await session.ReceiveAsync(TimeSpan.FromSeconds(60));
// ...
I am not exactly sure how to explain this so I'll give it my best shot.
Basically I have an application that connects to DropBox. One of the situations I have run into is with the registering process. At the moment during the registration process it connects to DropBox using the default browser, which it then requires the user to login and click allow app to use the service. In return you get a token which the app can use to connect to the service with. The problem I am having is getting the application to wait until the above process is completed. The only way I have figured out to get it to wait is to use system.threading(int). however if the person takes longer then the timeout then it fails to register properly.
I am hoping someone may be able to point me in the right direction and get it to wait without the threading function. I was hoping I could use a if loop or something but i have no idea how to do that properly.
here is the actual Oauth code:
private static OAuthToken GetAccessToken()
{
string consumerKey = "*****";
string consumerSecret = "****";
var oauth = new OAuth();
var requestToken = oauth.GetRequestToken(new Uri(DropboxRestApi.BaseUri), consumerKey, consumerSecret);
var authorizeUri = oauth.GetAuthorizeUri(new Uri(DropboxRestApi.AuthorizeBaseUri), requestToken);
Process.Start(authorizeUri.AbsoluteUri);
return oauth.GetAccessToken(new Uri(DropboxRestApi.BaseUri), consumerKey, consumerSecret, requestToken);
}
and here is the complete oauth function that is called when the registration button is clicked:
var accesstoken = GetAccessToken();
You need to make the Async (asynchronous) version of their GetAccessToken call. One that will call some function of yours when it is complete.
You could also loop until the information is ready, e.g.
while (dataIsNotReady()) {
Thread.Sleep(1000); // sleep for a bit. this is bad, locks up entire thread maybe even application while it sleeps. Make it shorter for less impact.
// TODO add a "timeout", i.e. only try this for X amount of time before breaking out
}
// Now we data is ready let's go
Update:
Perhaps you are better off using a library that can do it async for you e.g. this Dropbox C# library: https://github.com/dkarzon/DropNet