{"record":{"id":"88fee158bfbc078e","repo":"hcengineering/platform","slug":"request-hang-found","errorCode":null,"errorMessage":"request hang found","messagePattern":"request hang found","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"foundations/server/packages/server/src/sessionManager.ts","lineNumber":400,"sourceCode":"            this.ctx.error('failed to close', err)\n          })\n          continue\n        }\n        if (\n          lastRequestDiff + (1 / 10) * lastRequestDiff > this.timeouts.pingTimeout &&\n          now - s.session.lastPing > this.timeouts.pingTimeout\n        ) {\n          // We need to check state and close socket if it broken\n          // And ping other wize\n          s.session.lastPing = now\n          if (s.socket.checkState()) {\n            void s.socket.send(this.ticksContext, { result: pingConst }, s.session.binaryMode, s.session.useCompression)\n          }\n        }\n        for (const r of s.session.requests.values()) {\n          const sec = Math.round((now - r.start) / 1000)\n          if (sec > 0 && sec % hangRequestTimeoutSeconds === 0) {\n            this.ctx.warn('request hang found', {\n              sec,\n              wsId,\n              total: s.session.requests.size,\n              user: s.session.getUser(),\n              params: cutObjectArray(r.params)\n            })\n          }\n        }\n      }\n    }\n  }\n\n  createSession (token: Token, workspace: WorkspaceIds, info: LoginInfoWithWorkspaces): Session {\n    let primarySocialId: PersonId\n    let role: AccountRole = info.workspaces[workspace.uuid]?.role ?? AccountRole.User\n    switch (info.account) {\n      case systemAccountUuid:\n        primarySocialId = core.account.System","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/server/packages/server/src/sessionManager.ts#L382-L418","documentation":"For each active session request, the session tick checks how long it has been running; every hangRequestTimeoutSeconds it logs this warning with elapsed seconds, workspace, pending request count, user, and truncated request params. It identifies server-side requests (RPC) that never completed, typically because the client disconnected mid-request or the operation is genuinely stuck.","triggerScenarios":"handleSessionTick iterates session.requests and finds a request whose start time exceeds a multiple of hangRequestTimeoutSeconds — long-running queries, deadlocks, or requests belonging to hung clients that will never read the response.","commonSituations":"Heavy queries over large workspaces exceeding the timeout; awaited downstream calls (storage, kafka, DB) blocked; clients disconnected while request still executing; repeated logs for the same request indicate a truly stuck operation.","solutions":["Identify the stuck request via the logged params/wsId and profile the corresponding handler","Optimize long-running queries or add streaming/pagination so they finish under the timeout","Check downstream dependencies (datalake, DB, Kafka) for latency or deadlock","Raise hangRequestTimeoutSeconds only if requests legitimately take longer; repeated warnings mean a real leak"],"exampleFix":"// before\nawait findAll(ctx, clazz, { limit: 1000000 })\n// after\nawait findAll(ctx, clazz, { limit: 1000, ...page }) // paginate under timeout","handlingStrategy":"try-catch","validationCode":"const started = Date.now()\nconst result = await withTimeout(clientRequest, hangRequestTimeoutSeconds * 1000)\nfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n  return Promise.race([p, new Promise<T>((_, rej) => setTimeout(() => rej(new Error('client-side request timeout')), ms))])\n}","typeGuard":"function isLongRunning(r: { start: number }, thresholdSec: number): boolean {\n  return (Date.now() - r.start) / 1000 > thresholdSec\n}","tryCatchPattern":"try {\n  await request\n} catch (err) {\n  if (isTimeoutError(err)) {\n    logger.warn('request exceeded hang threshold', { elapsed: Date.now() - start })\n    // cancel and retry with smaller scope/pagination\n  } else throw err\n}","preventionTips":["Paginate large findAll queries to keep requests short","Add server-side timeouts to downstream calls (DB, storage)","Include request ids in logs to correlate 'request hang found' entries","Alert when the same request id is logged multiple ticks in a row"],"tags":["session","requests","timeout"],"backgroundTag":"hung-request-detected","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}