ai-chatbot/lib/canvas/image-concurrency.ts

88 lines
2.7 KiB
TypeScript

import "server-only";
import { normalizeCanvasImageTaskQueueConfig } from "./image-task-config";
const stateKey = "__unrestricted_canvas_image_models__";
type ModelState = { running: Set<string>; durations: number[] };
function getModels() {
const globalState = globalThis as typeof globalThis & {
[stateKey]?: Map<string, ModelState>;
};
return (globalState[stateKey] ??= new Map());
}
function getModel(key: string) {
const models = getModels();
const normalized = normalizeCanvasImageModelKey(key);
let state = models.get(normalized);
if (!state) {
state = { running: new Set(), durations: [] };
models.set(normalized, state);
}
return state;
}
export function normalizeCanvasImageModelKey(value: unknown) {
return typeof value === "string" && value.trim() ? value.trim() : "__default__";
}
export async function getCanvasImageTaskQueueConfig() {
return normalizeCanvasImageTaskQueueConfig(undefined);
}
export async function getCanvasImageSingleModelConcurrency() {
return 0;
}
export async function getCanvasImageBatchDispatchIntervalMs() {
return 0;
}
export function getCanvasImageRunningCountForModel(modelKey: string) {
return getModels().get(normalizeCanvasImageModelKey(modelKey))?.running.size || 0;
}
export type CanvasImageModelQueueStatus = {
status: "pending" | "running" | "succeeded" | "failed";
queuePosition: number;
sameModelPendingCount: number;
sameModelRunningCount: number;
concurrencyLimit: number;
estimatedWaitMs: number;
source: "model_queue";
};
export async function getCanvasImageModelQueueStatus(params: {
modelKey: string;
}): Promise<CanvasImageModelQueueStatus> {
return {
status: "running",
queuePosition: 0,
sameModelPendingCount: 0,
sameModelRunningCount: getCanvasImageRunningCountForModel(params.modelKey),
concurrencyLimit: 0,
estimatedWaitMs: 0,
source: "model_queue",
};
}
export function recordCanvasImageModelExecutionDuration(modelKey: string, durationMs: number) {
if (!Number.isFinite(durationMs) || durationMs <= 0) return;
const state = getModel(modelKey);
state.durations.push(durationMs);
if (state.durations.length > 24) state.durations.shift();
}
// Keep execution tracking/release semantics, without model or owner admission limits.
export async function acquireCanvasImageModelSlot(params: {
modelKey: string;
ownerKey?: string;
debugLabel?: string;
debugMeta?: Record<string, unknown>;
onQueued?: (status: CanvasImageModelQueueStatus) => void | Promise<void>;
}) {
const state = getModel(params.modelKey);
const ticket = crypto.randomUUID();
state.running.add(ticket);
return {
release: async () => {
state.running.delete(ticket);
},
waitMs: 0,
maxConcurrent: 0,
batchDispatchIntervalMs: 0,
};
}