{"record":{"id":"b8412295b21ecada","repo":"MHSanaei/3x-ui","slug":"traffic-writer-queue-full","errorCode":null,"errorMessage":"traffic writer queue full","messagePattern":"traffic writer queue full","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/traffic_writer.go","lineNumber":168,"sourceCode":"\t\ttwMu.Unlock()\n\t\treturn safeApply(fn)\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\ttwMu.Unlock()\n\t\treturn safeApply(fn)\n\tdefault:\n\t}\n\n\ttimer := time.NewTimer(trafficWriterSubmitTimeout)\n\tdefer timer.Stop()\n\tselect {\n\tcase queue <- req:\n\t\ttwMu.Unlock()\n\tcase <-timer.C:\n\t\ttwMu.Unlock()\n\t\treturn errors.New(\"traffic writer queue full\")\n\t}\n\n\tselect {\n\tcase err := <-req.done:\n\t\treturn err\n\tcase <-done:\n\t\tselect {\n\t\tcase err := <-req.done:\n\t\t\treturn err\n\t\tdefault:\n\t\t\treturn errors.New(\"traffic writer stopped before write completed\")\n\t\t}\n\t}\n}\n","sourceCodeStart":150,"sourceCodeEnd":183,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/traffic_writer.go#L150-L183","documentation":"The traffic writer is a single goroutine that serializes all DB writes through a bounded channel (capacity 256, see trafficWriterQueueSize in internal/web/service/traffic_writer.go:17). submitTrafficWrite holds twMu, waits up to trafficWriterSubmitTimeout (5s) for a free queue slot, and returns this error when the timer fires first. It means the writer goroutine is draining slower than callers are producing write requests — classic backpressure, typically caused by slow disk/SQLite lock contention or a burst of admin mutations colliding with the every-5s traffic poll.","triggerScenarios":"More than 256 pending runSerializedTx submissions (client/inbound edits, traffic resets) while the consumer goroutine is blocked on a slow DB transaction; e.g. a bulk client import or scripted API loop issuing many inbound updates at once, or SQLite stuck on a busy_timeout against a long reader.","commonSituations":"SQLite on a slow/network volume, Postgres deadlock retries serializing behind one transaction, automation scripts hammering /panel/api inbound update endpoints, or a hung DB connection making the single writer goroutine stall while the queue fills.","solutions":["Check DB health: for SQLite look for 'database is locked' in logs; for Postgres look for SQLSTATE 40P60/40P01 deadlocks or long transactions (pg_stat_activity) that are stalling the single writer goroutine.","Throttle the caller: batch inbound/client mutations instead of issuing hundreds of individual API calls within 5 seconds.","Move the database to faster storage or switch to PostgreSQL (XUI_DB_TYPE=postgres) so each serialized transaction completes quicker.","If the condition is chronic, raise trafficWriterQueueSize and/or trafficWriterSubmitTimeout in internal/web/service/traffic_writer.go:17-18 and rebuild — but only after fixing the underlying slow-write cause."],"exampleFix":"// before (caller loop filling the queue)\nfor _, c := range clients {\n    inboundService.UpdateClientTraffic(c) // may hit \"traffic writer queue full\"\n}\n\n// after: batch into one serialized transaction\nerr := inboundService.UpdateClientsTraffic(clients) // one submitTrafficWrite","handlingStrategy":"retry","validationCode":"// Not directly callable from outside the package; callers of inbound/client\n// service methods can shed load before bursts:\nif len(pendingMutations) > 200 { // queue is 256 deep\n    waitOrBatch()\n}","typeGuard":null,"tryCatchPattern":"err := svc.UpdateClient(...)\nif err != nil && strings.Contains(err.Error(), \"traffic writer queue full\") {\n    time.Sleep(trafficWriterSubmitTimeout) // let the writer drain\n    err = svc.UpdateClient(...)            // one bounded retry\n}\nreturn err","preventionTips":["Batch bulk client/inbound edits into a single API call instead of hundreds of individual requests.","Keep DB latency low: fast disk for SQLite, or Postgres with no long-running transactions contending on client_traffics/inbounds rows.","Monitor for this message in logs during automation runs; it is the earliest signal the serialized writer is saturating."],"tags":["concurrency","backpressure","database","sqlite","postgres"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}