{"record":{"id":"510feee8de97ce34","repo":"redis/redis-py","slug":"health-check-event-loop-failed-to-start-within-ti","errorCode":null,"errorMessage":"Health check event loop failed to start within {timeout} seconds","messagePattern":"Health check event loop failed to start within (.+?) seconds","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"redis/background.py","lineNumber":254,"sourceCode":"            )\n            self._health_check_thread.start()\n\n            # Wait for loop to be running INSIDE the lock with a timeout.\n            # This prevents other threads from trying to create another loop\n            # before this one is fully started, while avoiding permanent deadlock\n            # if the background thread fails to start the loop.\n            if not self._health_check_loop_ready.wait(timeout=timeout):\n                # Timeout expired - the loop failed to start\n                # Clean up the failed loop to allow retry\n                failed_loop = self._health_check_loop\n                self._health_check_loop = None\n                if failed_loop in self._event_loops:\n                    self._event_loops.remove(failed_loop)\n                try:\n                    failed_loop.close()\n                except Exception:\n                    pass\n                raise RuntimeError(\n                    f\"Health check event loop failed to start within {timeout} seconds\"\n                )\n\n    def _run_health_check_loop(self):\n        \"\"\"Run the shared health check event loop.\"\"\"\n        asyncio.set_event_loop(self._health_check_loop)\n\n        # Signal that the loop is ready before running\n        # Use call_soon to signal after run_forever starts processing\n        self._health_check_loop.call_soon(self._health_check_loop_ready.set)\n\n        try:\n            self._health_check_loop.run_forever()\n        finally:\n            try:\n                pending = asyncio.all_tasks(self._health_check_loop)\n                for task in pending:\n                    task.cancel()","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/background.py#L236-L272","documentation":"Raised as RuntimeError in BackgroundScheduler._ensure_health_check_loop when the health-check event loop fails to signal readiness within the timeout (default 5.0s). The background thread is supposed to set _health_check_loop_ready once asyncio.run_forever begins; if it never does, the loop is unusable. The code cleans up the failed loop so a retry can attempt a fresh one.","triggerScenarios":"run_coro_sync or run_coro_fire_and_forget triggers _ensure_health_check_loop, the daemon thread is started, but _health_check_loop_ready.wait(timeout) returns False — the thread never reached the set() call, e.g. thread startup blocked, loop creation failed, or the system is starved of resources.","commonSituations":"System under extreme load / thread starvation so the daemon thread does not get scheduled within 5s. Thread creation blocked by resource limits (ulimit -u) or a restricted runtime. A bug or exception inside _run_health_check_loop before it sets the ready event. CI environment with constrained CPU.","solutions":["Retry the operation — _ensure_health_check_loop cleans up the failed loop and a subsequent call creates a new one.","Reduce system load or raise thread/resource limits (ulimit -u) so the daemon thread can start promptly.","Increase the readiness timeout by calling a code path that passes a larger timeout if exposed, or investigate _run_health_check_loop for exceptions.","Check logs for exceptions from the health-check thread that prevented readiness signaling."],"exampleFix":"# before: single attempt fails under load\nresult = scheduler.run_coro_sync(hc, client, timeout=10)  # RuntimeError\n# after: retry with backoff\nfor attempt in range(3):\n    try:\n        result = scheduler.run_coro_sync(hc, client, timeout=10)\n        break\n    except RuntimeError:\n        time.sleep(1)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        return scheduler.run_coro_sync(hc, client, timeout=10)\n    except RuntimeError as e:\n        if \"failed to start\" in str(e):\n            await asyncio.sleep(backoff)\n            continue\n        raise","preventionTips":["Raise thread/resource limits on hosts running the background scheduler.","Retry loop startup — the failed loop is cleaned up for reuse."],"tags":["background","event-loop","threading","resource-limits"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}