Broker sessions rest while nothing needs them

A firm's client used to stay logged in around the clock, renewing on a fixed
timer overnight and at weekends. Now, once a firm has nothing open, nothing
pending and nothing left to trade before its next session for a random
15–45 minutes, its client disconnects and the dashboard shows it Resting.
It logs back in a random 20–50 minutes before the next session opens, at a
check-in every 3–7 Central daytime hours, or at once when trading starts, a
manual leg, copy trade, manual order or AutoBuyer run needs it. Token
renewals fall at random points (Tradovate 15–45 min before expiry, TopstepX
every 45–150 min). Settings → Trading → Rest idle broker sessions
(session_rest) turns it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-21 13:28:47 -05:00
co-authored by Claude Opus 5.5
parent 6dd2528fe2
commit 5eb0ea7760
18 changed files with 872 additions and 41 deletions
+9 -5
View File
@@ -1,7 +1,7 @@
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { NextResponse } from 'next/server';
import { getClients } from '@/lib/clients';
import { getClients, sessionRestEnabled, sessionRestInfo } from '@/lib/clients';
import { getTradableFirms } from '@/lib/firm-catalog';
import { getSchedulerHealth, getSchedulerStatus } from '@/lib/auto-trade';
import { getBuildVersion } from '@/lib/version';
@@ -41,20 +41,24 @@ export async function GET() {
const entries = getTradableFirms().map((firm) => {
const base = { firmId: firm.id, firm: firm.name, platform: firm.platform };
const client = clients.get(firm.id);
if (!client) return { ...base, hasClient: false, ready: false, accounts: 0 };
if (!client) return { ...base, hasClient: false, ready: false, resting: null, accounts: 0 };
const ready = isClientReady(client, now);
const accounts = client.accountList.length;
// Logged out on purpose while nothing needs it (lib/clients.ts):
// not ready, and nothing wrong.
const resting = sessionRestInfo(firm.id);
try {
return { ...base, hasClient: true, ready, accounts, ...client.health() };
return { ...base, hasClient: true, ready, resting, accounts, ...client.health() };
} catch (err) {
// One client's broken health() must not hide the rest.
return { ...base, hasClient: true, ready, accounts, healthError: errorMessage(err) };
return { ...base, hasClient: true, ready, resting, accounts, healthError: errorMessage(err) };
}
});
return NextResponse.json({
ok: entries.every((e) => !e.hasClient || e.ready),
ok: entries.every((e) => !e.hasClient || e.ready || !!e.resting),
sessionRest: sessionRestEnabled(),
now,
uptimeSec: Math.round(process.uptime()),
version: getBuildVersion(),