-
Notifications
You must be signed in to change notification settings - Fork 173
fix(csharp/src/Drivers/Databricks): Make mandatory token exchange blocking and fix concurrent handling #3715
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
fix(csharp/src/Drivers/Databricks): Make mandatory token exchange blocking and fix concurrent handling #3715
Conversation
…cking Changed the token exchange from a non-blocking background operation to a blocking synchronous operation. This ensures that requests use the exchanged token rather than the original non-Databricks token, which would fail authentication. Key changes: - Removed Task.Run wrapper and background thread offloading - Token exchange now blocks the request until completion - Simplified code by removing _pendingTokenTask tracking and Dispose method - Falls back to original token if exchange fails with clearer error message 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…dling Fixed issues with the blocking token exchange implementation: - Handle concurrent requests with different tokens properly - Serialize token exchanges to prevent race conditions - Track which token is currently being exchanged with _tokenBeingExchanged - When a different token arrives during an exchange, wait for completion then start new exchange - Maintain single-token cache to prevent unbounded memory growth Key changes: - Added _tokenBeingExchanged field to track ongoing exchanges - Updated PerformTokenExchangeIfNeeded to serialize exchanges for different tokens - Removed _lastSeenToken check from NeedsTokenExchange to avoid race conditions - Updated test to verify all concurrent requests use exchanged token - Added System.Linq using for LINQ operations in tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The field was set but never read for decision-making. The logic works correctly without it since we serialize exchanges using _pendingExchange and check _lastSeenToken to determine if a token was already processed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
alexguo-db
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline. The extend lifetime token exchange can be non-blocking, because the original token is a valid OAuth token. The mandatory token exchange can be non-blocking for AAD tokens issued from Azure Databricks since the original token is valid, but it must be blocking for workload identity federation because the original token is only used for token exchange (and can't access Databricks resources directly).
we should make the extend lifetime token exchange non blocking to ensure we are not increasing the query time. also do we have token cache for SSO? we should avoid calling the endpoint for every query/requests. |
We are caching the token. It is not calling the endpoint for every request, for a single httpConnection handler it will only do it for once. |
Summary
Problem
The previous non-blocking implementation had two issues:
First request would fail: The handler would send the first request with the original non-Databricks token (e.g., Azure AD, AWS IAM) while starting token exchange in the background. Since this is mandatory token exchange, the non-Databricks token would fail authentication with Databricks.
Different tokens not handled correctly: When multiple requests came in with different tokens, the second token would not be exchanged properly if it arrived during the first token's exchange. The second request would wait for the first token's exchange, then return without starting its own exchange.
Solution
awaitTask.Runbackground thread offloading - exchange happens on the calling thread_pendingTokenTasktracking complexityDisposemethod (no longer needed without background tasks)_lastSeenTokencheck fromNeedsTokenExchangeto avoid race conditionsImplementation Details
The key insight is to serialize all token exchanges:
This ensures:
Test plan
🤖 Generated with Claude Code