{"record":{"id":"f4f89c5a5bd3d649","repo":"iflytek/astron-agent","slug":"session-closed-and-retry-failed-error","errorCode":null,"errorMessage":"Session closed and retry failed: {error}","messagePattern":"Session closed and retry failed: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"core/knowledge/infra/ragflow/ragflow_client.py","lineNumber":302,"sourceCode":"    attempt: int, max_retries: int, error: Exception\n) -> None:\n    \"\"\"\n    Handle session closed errors with retry logic\n\n    Args:\n        attempt: Current attempt number\n        max_retries: Maximum retry attempts\n        error: The error that occurred\n\n    Raises:\n        Exception: If max retries exceeded\n    \"\"\"\n    global _session_cache\n    _session_cache = None\n    logger.warning(f\"Session closed, retrying... (attempt {attempt + 1}/{max_retries})\")\n\n    if attempt == max_retries - 1:\n        raise Exception(f\"Session closed and retry failed: {error}\")\n    return None  # This should never be reached but satisfies mypy\n\n\nasync def _make_request(\n    method: str,\n    endpoint: str,\n    data: Optional[Dict[str, Any]] = None,\n    files: Optional[Dict[str, Any]] = None,\n) -> Dict[str, Any]:\n    \"\"\"\n    Common function for sending HTTP requests\n\n    Args:\n        method: HTTP method\n        endpoint: API endpoint\n        data: Request data\n        files: File data\n","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/knowledge/infra/ragflow/ragflow_client.py#L284-L320","documentation":"When an aiohttp session has been closed underneath an in-flight request, _make_request retries via _handle_session_error, which clears the cached global session. If the failure still occurs on the last allowed retry (attempt == max_retries - 1), it raises Exception('Session closed and retry failed: {error}'), signaling that session recycling did not recover the connection.","triggerScenarios":"Calling any _make_request-backed RAGFlow operation while the cached aiohttp ClientSession is closed (e.g. after event-loop shutdown/restart, keepalive timeout on the server, or session garbage collection), and retries are exhausted.","commonSituations":"Long-lived service whose cached session outlived server keepalive; tests closing the loop/session between cases; deploying code that recreates the event loop while the module-level _session_cache persists; RAGFlow server restarting and dropping keepalive connections.","solutions":["Call cleanup_session() (or recreate the session) after loop/session lifecycle events and re-issue the request","Reduce session reuse issues by checking session.closed before reuse and proactively recreating","Investigate why the underlying error repeated across retries (server availability, proxy timeouts)","If keepalive is the cause, tune server/aiohttp keepalive timeouts so idle sessions are refreshed before the server drops them"],"exampleFix":"# before\nawait ragflow_retrieve(dataset_id, query)\n# after\ntry:\n    await ragflow_retrieve(dataset_id, query)\nexcept Exception as e:\n    if 'Session closed' in str(e):\n        await cleanup_session()\n        result = await ragflow_retrieve(dataset_id, query)","handlingStrategy":"retry","validationCode":"import aiohttp\nfrom core.knowledge.infra.ragflow import ragflow_client as rc\nasync def session_usable() -> bool:\n    s = rc._session_cache\n    return s is not None and not s.closed","typeGuard":null,"tryCatchPattern":"try:\n    result = await ragflow_call(...)\nexcept Exception as e:\n    if 'Session closed and retry failed' in str(e):\n        await cleanup_session()\n        result = await ragflow_call(...)  # fresh session","preventionTips":["Call cleanup_session() on shutdown and after event-loop recreation","Avoid sharing the module-level session across different event loops (e.g. tests)","Keep RAGFlow server keepalive settings compatible with client session reuse"],"tags":["aiohttp","session","retry","ragflow"],"backgroundTag":"connection-refused","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}