maxpool 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Multi-account Claude Code proxy with adaptive, rate-aware load balancing across Claude accounts",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/config.js CHANGED
@@ -36,6 +36,12 @@ export function createDefaultConfig() {
36
36
  apiKey: 'mp-' + randomBytes(24).toString('base64url'),
37
37
  },
38
38
  upstream: 'https://api.anthropic.com',
39
+ // Per-account "stop using this account" gate, applied to BOTH the 5h
40
+ // session window and the 7d weekly window (whichever utilization is
41
+ // higher). 0.90 = stop routing to an account once it crosses 90% of a
42
+ // window, leaving a 10% safety margin so it is never hard-limited (429).
43
+ // Raise toward 0.97 to squeeze more out of accounts before rotating
44
+ // (less margin, slightly higher 429 risk); lower to rotate more eagerly.
39
45
  switchThreshold: 0.90,
40
46
  quotaProbeSeconds: 0, // background quota probe; 0 = off (opt-in)
41
47
  routing: {
@@ -48,11 +54,28 @@ export function createDefaultConfig() {
48
54
  safetyMaxGlobalActive: 150,
49
55
  cooldownMs: 30_000,
50
56
  maxCooldownMs: 15 * 60_000,
57
+ // Weekly (7d) quota tiers — how aggressively to de-prioritise an account
58
+ // as its weekly usage climbs. Each is a fraction (0..1) of the weekly
59
+ // limit. Below soft = full speed; soft..reserve = mild penalty;
60
+ // reserve..critical = heavy penalty; above exhausted = effectively
61
+ // parked until the weekly window resets. Tune to trade burst capacity
62
+ // against weekly-limit safety.
63
+ weeklySoftThreshold: 0.65,
64
+ weeklyReserveThreshold: 0.85,
65
+ weeklyCriticalThreshold: 0.95,
66
+ weeklyExhaustedThreshold: 0.985,
51
67
  },
52
68
  retry: {
53
69
  maxAttemptsPerRequest: 0,
54
70
  maxRetryBufferBytes: 10 * 1024 * 1024,
55
71
  },
72
+ // On quit (q / Ctrl-C / SIGTERM): stop accepting new requests, give
73
+ // in-flight requests up to drainTimeoutMs to finish, then force-exit.
74
+ // A second signal forces an immediate exit. Kept short so quit works
75
+ // under a continuous request flood instead of hanging.
76
+ shutdown: {
77
+ drainTimeoutMs: 15_000,
78
+ },
56
79
  queue: {
57
80
  enabled: true,
58
81
  maxWaitMs: 24 * 60 * 60 * 1000,
package/src/index.js CHANGED
@@ -193,7 +193,11 @@ async function serverWorkerCommand() {
193
193
  let syncTimer = null;
194
194
  let draining = false;
195
195
  let restartController = null;
196
- const drainTimeoutMs = Math.max(1000, Number(config.shutdown?.drainTimeoutMs) || 10 * 60_000);
196
+ // Quit drains in-flight requests, then force-exits. Kept short so a single
197
+ // 'q' / Ctrl-C / SIGTERM actually quits under a continuous request flood
198
+ // (where there are always active requests) instead of waiting indefinitely.
199
+ // A second signal forces an immediate exit. Override via config.shutdown.drainTimeoutMs.
200
+ const drainTimeoutMs = Math.max(1000, Number(config.shutdown?.drainTimeoutMs) || 15_000);
197
201
  const hooks = {
198
202
  onRequestStart: (id, info) => {
199
203
  const accepted = restartController.requestStarted(id);
@@ -242,7 +246,7 @@ async function serverWorkerCommand() {
242
246
  if (tui?.running) tui.stop();
243
247
 
244
248
  console.log(`\n[Maxpool] Draining shutdown (${reason}).`);
245
- console.log(`[Maxpool] Stopped accepting new requests; waiting for ${restartController.activeRequests.size} active request(s). Press Ctrl-C again to force.`);
249
+ console.log(`[Maxpool] Stopped accepting new requests; waiting up to ${Math.ceil(drainTimeoutMs / 1000)}s for ${restartController.activeRequests.size} active request(s), then forcing exit. Press Ctrl-C again to force now.`);
246
250
 
247
251
  let done = false;
248
252
  let reportTimer = null;