🚦 fix: Gate Chat Starts During Readiness (#13502)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run

* fix: guard chat starts during server readiness

* style: format readiness retry condition

* fix: clarify chat start retry diagnostics

* fix: cancel stale chat start retries

* style: use const for retry timeout
This commit is contained in:
Danny Avila 2026-06-04 00:09:10 -04:00 committed by GitHub
parent 1da789bac0
commit 15072467b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 257 additions and 24 deletions

View file

@ -56,6 +56,30 @@ const trusted_proxy = Number(TRUST_PROXY) || 1; /* trust first proxy by default
const app = express();
let serverReady = false;
const SERVER_NOT_READY_CODE = 'SERVER_NOT_READY';
const CHAT_START_RETRY_AFTER_SECONDS = '1';
const rejectChatStartsUntilReady = (req, res, next) => {
if (serverReady || req.method !== 'POST' || req.path === '/abort') {
return next();
}
res.set('Retry-After', CHAT_START_RETRY_AFTER_SECONDS);
return res.status(503).json({
code: SERVER_NOT_READY_CODE,
error: 'Server is still starting. Please retry shortly.',
});
};
const configureGenerationStreams = () => {
const streamServices = createStreamServices();
GenerationJobManager.configure({
...streamServices,
cleanupOnComplete: !isEnabled(process.env.STREAM_KEEP_COMPLETED_JOBS),
});
GenerationJobManager.initialize();
};
const startServer = async () => {
const { metricsMiddleware, metricsRouter } = createMetrics();
if (!process.env.METRICS_SECRET) {
@ -214,6 +238,7 @@ const startServer = async () => {
app.use('/images/', createValidateImageRequest(appConfig.secureImageLinks), routes.staticRoute);
app.use('/api/share', preAuthTenantMiddleware, routes.share);
app.use('/api/roles', routes.roles);
app.use('/api/agents/chat', rejectChatStartsUntilReady);
app.use('/api/agents', routes.agents);
app.use('/api/banner', routes.banner);
app.use('/api/memories', routes.memories);
@ -251,6 +276,8 @@ const startServer = async () => {
/** Error handler (must be last - Express identifies error middleware by its 4-arg signature) */
app.use(ErrorController);
configureGenerationStreams();
const server = app.listen(port, host, async (err) => {
if (err) {
logger.error('Failed to start server:', err);
@ -280,14 +307,6 @@ const startServer = async () => {
});
await checkMigrations();
// Configure stream services (auto-detects Redis from USE_REDIS env var)
const streamServices = createStreamServices();
GenerationJobManager.configure({
...streamServices,
cleanupOnComplete: !isEnabled(process.env.STREAM_KEEP_COMPLETED_JOBS),
});
GenerationJobManager.initialize();
const inspectFlags = process.execArgv.some((arg) => arg.startsWith('--inspect'));
if (inspectFlags || isEnabled(process.env.MEM_DIAG)) {
memoryDiagnostics.start();