The heartbeat scheduler enqueued runs even while a provider's monthly usage window was full, so every task burned its 3-attempt retry budget on instant quota failures within seconds and stayed dead forever - raising the limit (or restarting) never revived anything. - Park tasks (skip enqueue) while their provider is at its monthly_request_limit instead of creating runs doomed to fail - Exclude quota-blocked failures from the 3-attempt retry budget, retroactively reviving tasks abandoned by past filled windows - Share the gate message as PROVIDER_MONTHLY_LIMIT_MESSAGE and log quota-block transitions once per state change for diagnosability - Ignore landing/ (self-contained Next.js sub-project) and built-in skills/ (prompt content) in eslint so verify:ci lints only application code
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
export interface ProviderRateLimitStateRecord {
|
|
orgId: string;
|
|
providerId: string;
|
|
providerKey: string;
|
|
windowStart: string;
|
|
windowEnd: string;
|
|
monthlyRequestLimit: number;
|
|
requestCount: number;
|
|
inputCharCount: number;
|
|
outputCharCount: number;
|
|
remainingRequestCount: number;
|
|
exhausted: boolean;
|
|
}
|
|
|
|
export interface ProviderObservedRateLimitState {
|
|
requestLimit: number | null;
|
|
remainingRequests: number | null;
|
|
resetAt: string | null;
|
|
retryAfterMs: number | null;
|
|
rawStateJson: string;
|
|
}
|
|
|
|
export interface ProviderRateLimitObservationRecord extends ProviderObservedRateLimitState {
|
|
id: string;
|
|
orgId: string;
|
|
providerId: string;
|
|
providerKey: string;
|
|
model: string | null;
|
|
observedAt: string;
|
|
}
|
|
|
|
/**
|
|
* Exact message recorded on runs blocked by a provider's monthly usage window.
|
|
* The heartbeat scheduler matches task_runs.error_message against this string
|
|
* so quota-blocked attempts never consume a task's retry budget — the text is
|
|
* a cross-module contract and also matches rows written by earlier builds
|
|
* that inlined it.
|
|
*/
|
|
export const PROVIDER_MONTHLY_LIMIT_MESSAGE = "Provider monthly request limit has been reached.";
|
|
|
|
export function currentProviderUsageWindow(now = new Date()): { start: string; end: string } {
|
|
const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
|
|
return { start: start.toISOString(), end: end.toISOString() };
|
|
}
|