fix(usage): stop 429s with an activity-dependent poll cadence + manual refresh
The usage monitor polled the undocumented OAuth usage endpoint every 60s and earned 429s. It now polls every 5 min while any task is Running and every 15 min while idle (usage_poll_interval_active_seconds / _idle_seconds, both clamped to >= 60; the old single usage_poll_interval_seconds key is gone). A 429 comes back as UsageRateLimitedException carrying Retry-After and adds exponential backoff on top, capped at 30 min and never shorter than the normal cadence; the strike count resets on the first success. The schedule arithmetic is the pure static UsagePollSchedule.NextDelay. Since the idle cadence is slow on purpose, WorkerHub.RefreshUsage drives UsageMonitorService.RefreshNowAsync behind a Refresh now button in the Usage Monitor modal: an out-of-band poll that pushes the loop's next-due time out so no double poll follows, with a 10s cooldown so click-spam can't earn a 429. Staleness now measures against the slower (idle) interval so an idle worker isn't flagged stale just for not polling.
This commit is contained in:
@@ -44,9 +44,18 @@ public sealed class WorkerConfig
|
||||
[JsonPropertyName("online_inbox")]
|
||||
public OnlineInboxConfig OnlineInbox { get; set; } = new();
|
||||
|
||||
/// <summary>Poll interval for the OAuth usage monitor. Clamped to a minimum of 15s on load.</summary>
|
||||
[JsonPropertyName("usage_poll_interval_seconds")]
|
||||
public int UsagePollIntervalSeconds { get; set; } = 60;
|
||||
/// <summary>
|
||||
/// Usage-monitor poll interval while at least one task is Running. Clamped to a minimum
|
||||
/// of 60s on load — the endpoint rate-limits (429) on tighter polling.
|
||||
/// </summary>
|
||||
[JsonPropertyName("usage_poll_interval_active_seconds")]
|
||||
public int UsagePollIntervalActiveSeconds { get; set; } = 300;
|
||||
|
||||
/// <summary>
|
||||
/// Usage-monitor poll interval while nothing is running. Clamped to a minimum of 60s on load.
|
||||
/// </summary>
|
||||
[JsonPropertyName("usage_poll_interval_idle_seconds")]
|
||||
public int UsagePollIntervalIdleSeconds { get; set; } = 900;
|
||||
|
||||
public static string DefaultConfigPath =>
|
||||
Path.Combine(Paths.AppDataRoot(), "worker.config.json");
|
||||
@@ -75,7 +84,8 @@ public sealed class WorkerConfig
|
||||
cfg.SandboxRoot = Paths.Expand(cfg.SandboxRoot);
|
||||
cfg.LogRoot = Paths.Expand(cfg.LogRoot);
|
||||
cfg.CentralWorktreeRoot = Paths.Expand(cfg.CentralWorktreeRoot);
|
||||
cfg.UsagePollIntervalSeconds = Math.Max(15, cfg.UsagePollIntervalSeconds);
|
||||
cfg.UsagePollIntervalActiveSeconds = Math.Max(60, cfg.UsagePollIntervalActiveSeconds);
|
||||
cfg.UsagePollIntervalIdleSeconds = Math.Max(60, cfg.UsagePollIntervalIdleSeconds);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user