feat(queue): implement queue scheduler service and API routes

- Added QueueSchedulerService to manage task queue lifecycle, including state machine, dependency resolution, and session management.
- Implemented HTTP API endpoints for queue scheduling:
  - POST /api/queue/execute: Submit items to the scheduler.
  - GET /api/queue/scheduler/state: Retrieve full scheduler state.
  - POST /api/queue/scheduler/start: Start scheduling loop with items.
  - POST /api/queue/scheduler/pause: Pause scheduling.
  - POST /api/queue/scheduler/stop: Graceful stop of the scheduler.
  - POST /api/queue/scheduler/config: Update scheduler configuration.
- Introduced types for queue items, scheduler state, and WebSocket messages to ensure type safety and compatibility with the backend.
- Added static model lists for LiteLLM as a fallback for available models.
This commit is contained in:
catlog22
2026-02-27 20:53:46 +08:00
parent 5b54f38aa3
commit 75173312c1
47 changed files with 3813 additions and 307 deletions

View File

@@ -3,6 +3,15 @@ import type { IncomingMessage } from 'http';
import type { Duplex } from 'stream';
import { a2uiWebSocketHandler, handleA2UIMessage } from './a2ui/A2UIWebSocketHandler.js';
import { handleAnswer } from '../tools/ask-question.js';
import type {
QueueWSMessageType,
QueueWSMessage,
QueueSchedulerStateUpdateMessage,
QueueItemAddedMessage,
QueueItemUpdatedMessage,
QueueItemRemovedMessage,
QueueSchedulerConfigUpdatedMessage,
} from '../types/queue-types.js';
// WebSocket clients for real-time notifications
export const wsClients = new Set<Duplex>();
@@ -622,3 +631,53 @@ export function broadcastCoordinatorLog(
timestamp: new Date().toISOString()
});
}
// Re-export Queue WebSocket types from queue-types.ts
export type {
QueueWSMessageType as QueueMessageType,
QueueSchedulerStateUpdateMessage,
QueueItemAddedMessage,
QueueItemUpdatedMessage,
QueueItemRemovedMessage,
QueueSchedulerConfigUpdatedMessage,
};
/**
* Union type for Queue messages (without timestamp - added automatically)
*/
export type QueueMessage =
| Omit<QueueSchedulerStateUpdateMessage, 'timestamp'>
| Omit<QueueItemAddedMessage, 'timestamp'>
| Omit<QueueItemUpdatedMessage, 'timestamp'>
| Omit<QueueItemRemovedMessage, 'timestamp'>
| Omit<QueueSchedulerConfigUpdatedMessage, 'timestamp'>;
/**
* Queue-specific broadcast with throttling
* Throttles QUEUE_SCHEDULER_STATE_UPDATE messages to avoid flooding clients
*/
let lastQueueBroadcast = 0;
const QUEUE_BROADCAST_THROTTLE = 1000; // 1 second
/**
* Broadcast queue update with throttling
* STATE_UPDATE messages are throttled to 1 per second
* Other message types are sent immediately
*/
export function broadcastQueueUpdate(message: QueueMessage): void {
const now = Date.now();
// Throttle QUEUE_SCHEDULER_STATE_UPDATE to reduce WebSocket traffic
if (message.type === 'QUEUE_SCHEDULER_STATE_UPDATE' && now - lastQueueBroadcast < QUEUE_BROADCAST_THROTTLE) {
return;
}
if (message.type === 'QUEUE_SCHEDULER_STATE_UPDATE') {
lastQueueBroadcast = now;
}
broadcastToClients({
...message,
timestamp: new Date().toISOString()
});
}