Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use async/await to allow for async storage #61

Merged
merged 1 commit into from
Jul 26, 2023

Conversation

splurgebudget
Copy link
Contributor

Changed the entire call tree to allow for async storage.

Also: Redid the way requests queue in the interceptor to remove a race condition.

If two interceptors were run back-to-back, it was possible for this to happen:

  1. Interceptor1 starts and checks isRefreshing - which is false so it skips the queue
  2. Interceptor1 then yields before getting to the isRefreshing = true in refreshToken
  3. Interceptor2 starts and checks isRefreshing - which is still false! So it skips the queue
  4. Interceptor1 runs and refreshes the token
  5. Interceptor2 runs and refreshes the token

Why didn't the (well designed!) test catch this before? Because there happened to not be any await calls in-between starting the interceptor and setting isRefreshing = true. However, this was a race condition waiting to happen (which it did - as soon as I added an await!)

My fix removes the queue and utilizes the native "queue" created by multiple waiters waiting on the same Promise. This is more robust due to the lack of distance between waiting and setting the Promise - and is quite a bit simpler.

@valentin-debris
Copy link

This PR arrives at the right time !

I'm starting a new react-native app that will use SecureStore from Expo, which use async calls, so for now, the custom Storage I made can't works due to the lack of supporting async/await.

Hope this will be releases soon :)

@splurgebudget
Copy link
Contributor Author

Yep - I made this for Expo SecureStore myself… it works great! You can always directly NPM install from my repo/branch if you want to. That’s how I’m working while I’m waiting on this to be merged.

@revmischa
Copy link
Member

Thanks for this work! This will need to be a new major version right, since it will break any existing users?

// Try to await a current request
if (currentlyRequestingPromise) accessToken = await currentlyRequestingPromise

if (!accessToken) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can return early here for clarity

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't return here - needs to fall through to the code below to set the headers and and the config.

Comment on lines +165 to +169
currentlyRequestingPromise = undefined
} catch (error: unknown) {
// Reset the promise
currentlyRequestingPromise = undefined

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can put this in a finally block, it will always get called

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand? No need for finally... we're using await.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait - I see what you are saying now. I thought you were referencing waiting on the Promise - but you were actually talking about setting it to undefined. Sure - that would be fine.

I don't actually know the semantics though - does a finally get run even if we rethrow like we are on 171? At any rate - I would say to hold off on that change until we get this in. What's here now matches up with the original code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does get called even if rethrowing, I believe the doc I linked is saying that
Not a big deal

@splurgebudget
Copy link
Contributor Author

splurgebudget commented Jul 19, 2023

Thanks for this work! This will need to be a new major version right, since it will break any existing users?

No problem! Glad to contribute!

A new major version might be a good idea. The upgrade will be pretty easy for most users... they really just need to add an await in front of setAuthTokens.

@revmischa
Copy link
Member

Can you bump the major version and we can merge it?

Redo the way requests queue in the interceptor to remove a race condition.

Bump the major version
@splurgebudget
Copy link
Contributor Author

@revmischa - done!

@revmischa revmischa merged commit 0647969 into jetbridge:master Jul 26, 2023
3 checks passed
@revmischa
Copy link
Member

Thanks for your work!

@revmischa
Copy link
Member

4.0.0 published

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants