fix(mission-control): increase rate limit for events/recent, add error handling
Some checks failed
ci/woodpecker/push/ci Pipeline failed

This commit is contained in:
2026-03-07 18:42:50 -06:00
parent 65536fcb75
commit e80b624ca6
2 changed files with 33 additions and 7 deletions

View File

@@ -146,7 +146,7 @@ export class AgentsController {
* Return recent orchestrator events for non-streaming consumers. * Return recent orchestrator events for non-streaming consumers.
*/ */
@Get("events/recent") @Get("events/recent")
@Throttle({ status: { limit: 200, ttl: 60000 } }) @Throttle({ default: { limit: 1000, ttl: 60000 } })
getRecentEvents(@Query("limit") limit?: string): { getRecentEvents(@Query("limit") limit?: string): {
events: ReturnType<AgentEventsService["getRecentEvents"]>; events: ReturnType<AgentEventsService["getRecentEvents"]>;
} { } {

View File

@@ -44,6 +44,25 @@ interface AuditLogResponse {
total: number; total: number;
page: number; page: number;
pages: number; pages: number;
notice?: string;
}
function createEmptyAuditLogResponse(page: number, notice?: string): AuditLogResponse {
return {
items: [],
total: 0,
page,
pages: 0,
...(notice !== undefined ? { notice } : {}),
};
}
function isRateLimitError(error: unknown): boolean {
if (!(error instanceof Error)) {
return false;
}
return /429|rate limit|too many requests/i.test(error.message);
} }
function isRecord(value: unknown): value is Record<string, unknown> { function isRecord(value: unknown): value is Record<string, unknown> {
@@ -138,7 +157,15 @@ async function fetchAuditLog(
params.set("sessionId", normalizedSessionId); params.set("sessionId", normalizedSessionId);
} }
return apiGet<AuditLogResponse>(`/api/mission-control/audit-log?${params.toString()}`); try {
return await apiGet<AuditLogResponse>(`/api/mission-control/audit-log?${params.toString()}`);
} catch (error) {
if (isRateLimitError(error)) {
return createEmptyAuditLogResponse(page, "Rate limited - retrying...");
}
return createEmptyAuditLogResponse(page);
}
} }
export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): React.JSX.Element { export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): React.JSX.Element {
@@ -180,11 +207,10 @@ export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): Rea
const totalItems = auditLogQuery.data?.total ?? 0; const totalItems = auditLogQuery.data?.total ?? 0;
const totalPages = auditLogQuery.data?.pages ?? 0; const totalPages = auditLogQuery.data?.pages ?? 0;
const items = auditLogQuery.data?.items ?? []; const items = auditLogQuery.data?.items ?? [];
const notice = auditLogQuery.data?.notice;
const canGoPrevious = page > 1; const canGoPrevious = page > 1;
const canGoNext = totalPages > 0 && page < totalPages; const canGoNext = totalPages > 0 && page < totalPages;
const errorMessage =
auditLogQuery.error instanceof Error ? auditLogQuery.error.message : "Failed to load audit log";
return ( return (
<Sheet open={open} onOpenChange={setOpen}> <Sheet open={open} onOpenChange={setOpen}>
@@ -237,10 +263,10 @@ export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): Rea
Loading audit log... Loading audit log...
</td> </td>
</tr> </tr>
) : auditLogQuery.error ? ( ) : notice ? (
<tr> <tr>
<td colSpan={5} className="px-3 py-6 text-center text-sm text-red-500"> <td colSpan={5} className="px-3 py-6 text-center text-sm text-muted-foreground">
{errorMessage} {notice}
</td> </td>
</tr> </tr>
) : items.length === 0 ? ( ) : items.length === 0 ? (