Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent from executing tasks in same time

I need advices about how to handle the oauth2 token refreshing in my app.

I'm using GRPC to make my http requests to my API which I'm connected with an oauth2 token (it expires after 1 hour).

Before launching every request, I check the token:

  • Up-to-date ? launch networkRequest

  • Out-dated ? launch refreshToken -> launch networkRequest

Everything seems to work well but in some cases, my client "lose" the token.

The problem is that for 2 requests A & B launched in the exact same time, if the token is outdated, they will both refresh it. My server will generate a newTokenA, return it, generate newTokenB (remove newTokenA), return it. If the response newTokenA arrives to the client after newTokenB, the client token token will not be the good one.

I used a Semaphore to ensure that one call the refreshToken is made at the same time.

But when my Semaphore is waiting, I don't receive any response from my server.

let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0)

func authenticate(completion: (GRPCProtoCall) -> (Void)) -> GRPCProtoCall {

    // Wait here if authenticate already called
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

     // If token up to date
    if isOAuth2TokenValid() {
        dispatch_semaphore_signal(semaphore) // Release semaphore
        completion(self.withAuthorization())
        return self
    }

    // Refresh the outdated token
    APIClient.shared.oAuth2AccessTokenRefresh { (response) -> (Void) in
        dispatch_semaphore_signal(semaphore)  // Release semaphore
        completion(self.withAuthorization())
    }

    return self
}
like image 844
Toldy Avatar asked May 26 '26 05:05

Toldy


1 Answers

I think your dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) holding your thread, you can try it with timeout incase last request does not response, and put it before return self

while semaphore.wait(timeout: DispatchTime.now() + Double(5000000000) / Double(NSEC_PER_SEC)) == DispatchTimeoutResult.success {//time out set to 5 seconds
    print("wait")
}
like image 110
Terence Avatar answered May 27 '26 20:05

Terence



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!