Skip to content

Fix race condition in lazy facilitator initialization#1812

Open
ayushozha wants to merge 1 commit intocoinbase:mainfrom
ayushozha:fix/concurrency-safe-lazy-facilitator-init
Open

Fix race condition in lazy facilitator initialization#1812
ayushozha wants to merge 1 commit intocoinbase:mainfrom
ayushozha:fix/concurrency-safe-lazy-facilitator-init

Conversation

@ayushozha
Copy link

Summary

Fixes #1584

  • FastAPI middleware: concurrent async requests could race on init_done flag, causing multiple simultaneous http_server.initialize() calls. Added asyncio.Lock with double-checked locking to ensure single-flight initialization.
  • Flask middleware: concurrent threads could race on self._init_done flag under threaded WSGI servers. Added threading.Lock with double-checked locking for thread-safe initialization.
  • Failed initialization does not permanently set init_done = True, so subsequent requests can retry.

Changes

File Change
python/x402/http/middleware/fastapi.py Added asyncio.Lock guard around lazy init
python/x402/http/middleware/flask.py Added threading.Lock guard around lazy init
python/x402/tests/unit/http/middleware/test_fastapi.py Added concurrency + retry tests
python/x402/tests/unit/http/middleware/test_flask.py Added concurrency + retry tests
python/x402/changelog.d/1584.bugfix.md Towncrier fragment

Test plan

  • test_concurrent_requests_initialize_only_once — fires 3 concurrent async requests at FastAPI middleware, asserts initialize() called exactly once
  • test_concurrent_threads_initialize_only_once — fires 5 concurrent threads at Flask middleware, asserts initialize() called exactly once
  • test_init_error_does_not_block_subsequent_requests — verifies failed init allows retry on next request (both frameworks)
  • All 66 existing + new middleware tests pass

cc @ethanoroshiba @CarsonRoscoe

… Flask middleware

Under concurrent requests, multiple coroutines/threads could see init_done=False
simultaneously and all call http_server.initialize(), causing redundant init calls
and inconsistent error propagation.

- FastAPI: guard with asyncio.Lock using double-checked locking pattern
- Flask: guard with threading.Lock using double-checked locking pattern
- Add concurrency tests proving single-flight initialization for both frameworks
- Add tests verifying failed init does not permanently block retries

Closes coinbase#1584
@cb-heimdall
Copy link

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

@vercel
Copy link

vercel bot commented Mar 25, 2026

@ayushozha is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions bot added sdk Changes to core v2 packages python labels Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python sdk Changes to core v2 packages

Development

Successfully merging this pull request may close these issues.

Make lazy facilitator initialization concurrency-safe

2 participants