# Fix: Critical Concurrency Errors in Multi-User Environments (Event Loop Fragmentation)
🚨 Problem Statement
The application currently experiences a RuntimeError: Timeout context manager should be used inside a task when multiple users access the app simultaneously or when a single user reloads their page. This failure prevents the app from being production-ready as it essentially limits usage to a single successful session at a time.
🔍 Root Cause Analysis
The issue stems from the "Per-User Loop" architecture implemented in the GitLabClient and other infrastructure modules.
1. Event Loop Fragmentation (The "Per-User" Loop Flaw)
Every time a new user logs in or a new GitLabClient is instantiated, the code performs the following:
self._loop = asyncio.new_event_loop()
self._thread = threading.Thread(target=self._run_event_loop, daemon=True)
self._thread.start()
In a Streamlit environment (which is multi-threaded by nature), this creates dozens of independent background threads and loops. These loops compete for CPU resources and struggle to stay synchronized with the main Streamlit threadpool.
2. Global Policy Corruption
Inside each GitLabClient, the following global call is made:
asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
set_event_loop_policy is a process-level global setting. When User A starts their client, they set the policy. When User B starts their client a second later, they overwrite User A's policy. This constant mutation of the global state causes asyncio to lose track of the "Current Task," leading to the specific Python 3.11+ error regarding the timeout context manager.
3. Task Context Loss
Modern asynchronous libraries (like glabflow and httpx) rely on asyncio.timeout(). This requires the calling context to be a valid asyncio.Task. In the fragmented architecture, the connection between the submitted coroutine and the running loop becomes "poisoned" by the global policy changes, causing the async machinery to fail.
📉 Impact
Non-Scalable: The app crashes as soon as a second person tries to use it.
Reload Failures: Refreshing the browser leaves "stale" threads and loops running, which prevent the new session from establishing a clean connection to GitLab.
Resource Leakage: Higher memory usage due to excessive background threads.
✅ Proposed Requirement
Refactor the infrastructure to move away from "Per-User" loops and implement a Single Global Asynchronous Bridge.
Initialize exactly one background event loop for the entire application.
Ensure all GitLabClient instances share this single loop.
Set the DefaultEventLoopPolicy only once at the application entry point (app.py).
🛠️ Requirements
Create a bridge.py singleton to manage the global loop.
Refactor GitLabClient to accept/fetch the shared loop.
Remove redundant loop creation logic from BatchClient and auxiliary helpers.