Skip to content

Conversation

@ptiurin
Copy link
Contributor

@ptiurin ptiurin commented May 15, 2025

Improving authentication mechanism.
Key Changes:

  • Fix a bug in token expiry calculation
  • Improved naming so it's clear what each variable represents, since there was a bug due to confusion
  • Added atomic (re)authentication eliminating the possibility of the token being empty
  • Improved feedback and logging so instead of sending a request that we know will fail we raise an error

@ptiurin ptiurin changed the title fix authentication mechanism fix(FIR-46131): Atomic authentication mechanism and token expiry May 15, 2025
@ptiurin ptiurin marked this pull request as ready for review May 15, 2025 14:15
@ptiurin ptiurin requested a review from a team as a code owner May 15, 2025 14:15
Copy link
Contributor

@bogdantruta-firebolt bogdantruta-firebolt left a comment

Choose a reason for hiding this comment

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

lgtm

}

// No cached token, acquire write lock and authenticate
await this.acquireWriteLockAndAuthenticate();
Copy link
Contributor

Choose a reason for hiding this comment

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

This function already does all the above inside of it. Can we just say authenticate == this.acquireWriteLockAndAuthenticate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

authenticate gets read lock to fetch the token then falls back to acquireWriteLockAndAuthenticate if looks like cached token needs to be refreshed. It's not equivalent since write lock prevents any other reads and read lock allows multiple locks to be acquired as long as there's no write lock.
Using acquireWriteLockAndAuthenticate would mean we're essentially introducing a bottleneck here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok I see. It's just the logic duplication confuses me. Can we either

  • Only acquire writeLock in acquireWriteLockAndAuthenticate after we've validated that no cache entry is present?
  • Don't check cache in that function at all and let outer function manage it
    At this point the fact that we check cache in multiple places seems confusing to me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have to check the cache twice. Once - under read lock. If it's not cached then we need to acquire write lock and write to it. However, there could be two "threads" at the same stage here and if one acquires a write lock first then it will refresh the token. There's no need for another "thread" to do the same since "thread" 1 has already done so. But we're under the same stage - past the initial check and before the authentication refresh, so after we acquired a write lock we check again that no other "thread" has refreshed the token while we were waiting on a lock.
This efficiency is especially crucial when we have customers that have 600 query/second bursts and if we're doing an auth each time it will grind to a halt.

}

private async tryGetCachedToken(): Promise<string | undefined> {
async reAuthenticate(): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this function just be replaced by adding a skipCache parameter to acquireWriteLockAndAuthenticate? Or just use it under the hood? Since currently a lot of logic seems to be duplicated in these two

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does a different thing, acquireWriteLockAndAuthenticate checks cache then performs auth, while this function clears cache under write lock and does auth. We can add a flag that would mean either cache is cleared or fetched, but I think it will hurt the readability - it will be another layer of ifs.

Copy link
Contributor

@stepansergeevitch stepansergeevitch May 19, 2025

Choose a reason for hiding this comment

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

Taking into account my previous confusion, WDYT about removing the cache check from acquireWriteLockAndAuthenticate to leave it a "single responsibility", and just use it in other functions which will take care of the cache?

@sonarqubecloud
Copy link

Copy link
Contributor

@stepansergeevitch stepansergeevitch left a comment

Choose a reason for hiding this comment

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

The logic makes sense. Approving to deliver the fix, but we should consider improving the readability later

@ptiurin ptiurin merged commit b47123e into main May 19, 2025
4 checks passed
@ptiurin ptiurin deleted the fix-auth-token-expiry branch May 19, 2025 14:10
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.

4 participants