Track HiveGrid Cloud planning reference

This commit is contained in:
david committed 2026-06-26 20:48:01 +02:00
1 parent b3d5ea6764
commit e341c5938a
5784 files changed
+1104929 -3

No files matched your search

@@ -0,0 +1,300 @@
import { describe, expect, test, vi } from "vitest";
import {
buildAiBrowserTaskJob,
buildAiChatCompletionJob,
buildAiEmbeddingJob,
buildBrowserSessionCleanupJob,
buildBrowserSessionRunJob,
buildBrowserUsageFlushJob,
buildCleanupJob,
buildExportJob,
buildFilePreviewJob,
buildFileScanJob,
buildImportJob,
buildNotificationJob,
buildPluginInvokeJob,
buildRetryJobOptions,
buildTransactionalMailJob,
buildWebhookDeliveryJob,
enqueueJob,
queueNames,
type ProducerJobDescriptor,
type QueueName,
type TypedQueue,
} from "../src/index.js";
import * as producerExports from "../src/producers.js";
type RetryMetrics = Pick<
ReturnType<typeof buildRetryJobOptions>,
"attempts" | "backoff" | "removeOnComplete" | "removeOnFail"
>;
const descriptorBuilders = {
buildAiBrowserTaskJob: () => buildAiBrowserTaskJob({ tenantId: "tenant_1", task: { action: "research" } }),
buildAiChatCompletionJob: () =>
buildAiChatCompletionJob({ tenantId: "tenant_1", messages: [{ role: "user", content: "Hello" }] }),
buildAiEmbeddingJob: () =>
buildAiEmbeddingJob({ tenantId: "tenant_1", messages: [{ role: "user", content: "Embed this" }] }),
buildBrowserSessionCleanupJob: () => buildBrowserSessionCleanupJob({ tenantId: "tenant_1", sessionId: "session_1" }),
buildBrowserSessionRunJob: () =>
buildBrowserSessionRunJob({ tenantId: "tenant_1", sessionId: "session_1", task: { action: "capture" } }),
buildBrowserUsageFlushJob: () => buildBrowserUsageFlushJob({ tenantId: "tenant_1", sessionId: "session_1" }),
buildCleanupJob: () => buildCleanupJob({ task: "expired-sessions" }),
buildExportJob: () =>
buildExportJob({
exportJobId: "export_job_metrics_1",
tenantId: "tenant_1",
requestedByUserId: "user_1",
exportType: "members",
format: "csv",
}),
buildFilePreviewJob: () =>
buildFilePreviewJob({ fileId: "file_1", tenantId: "tenant_1", bucket: "uploads", storageKey: "tenants/tenant_1/files/file_1/original", mimeType: "image/heic" }),
buildFileScanJob: () => buildFileScanJob({ bucket: "uploads", key: "tenant_1/upload_1/file.pdf" }),
buildImportJob: () =>
buildImportJob({
importJobId: "import_job_metrics_1",
tenantId: "tenant_1",
requestedByUserId: "user_1",
importType: "members",
format: "csv",
sourceBucket: "uploads",
sourceKey: "tenant_1/imports/members.csv",
}),
buildNotificationJob: () => buildNotificationJob({ tenantId: "tenant_1", userId: "user_1", channel: "in-app", messageKey: "message.ready" }),
buildPluginInvokeJob: () => buildPluginInvokeJob({ tenantId: "tenant_1", pluginId: "plugin_1", version: "1.0.0", hookName: "onEvent" }),
buildTransactionalMailJob: () => buildTransactionalMailJob({ to: ["user@example.com"], templateId: "welcome" }),
buildWebhookDeliveryJob: () => buildWebhookDeliveryJob({ url: "https://example.com/webhook", eventName: "entity.created" }),
} satisfies Record<string, () => ProducerJobDescriptor>;
function producerHelperExportNames(): string[] {
return Object.keys(producerExports)
.filter((name) => /^build[A-Z].*Job$/.test(name))
.sort();
}
function retryMetricsFor(descriptor: ProducerJobDescriptor): RetryMetrics {
const { attempts, backoff, removeOnComplete, removeOnFail } = buildRetryJobOptions(descriptor);
return { attempts, backoff, removeOnComplete, removeOnFail };
}
function sortedRetryMetricsSnapshot(): Record<string, RetryMetrics> {
return Object.fromEntries(
Object.values(descriptorBuilders)
.map((buildDescriptor) => {
const descriptor = buildDescriptor();
return [`${descriptor.queueName}:${descriptor.jobName}`, retryMetricsFor(descriptor)] as const;
})
.sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
);
}
function createMockQueue<Name extends QueueName>(): TypedQueue<Name> {
return { add: vi.fn().mockResolvedValue({ id: "queued-job" }) } as unknown as TypedQueue<Name>;
}
async function enqueueOptionsFor(descriptor: ProducerJobDescriptor, options?: Parameters<typeof enqueueJob>[2]) {
const queue = createMockQueue<typeof descriptor.queueName>();
await enqueueJob(queue, descriptor, options);
return vi.mocked(queue.add).mock.calls[0]?.[2];
}
describe("queue retry metrics snapshot", () => {
test("covers every exported producer descriptor helper", () => {
expect(Object.keys(descriptorBuilders).sort()).toEqual(producerHelperExportNames());
});
test("locks retry defaults for every queue producer descriptor", () => {
expect(sortedRetryMetricsSnapshot()).toMatchInlineSnapshot(`
{
"${queueNames.aiChatbot}:browser-task": {
"attempts": 2,
"backoff": {
"delay": 5000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.aiChatbot}:chat-completion": {
"attempts": 3,
"backoff": {
"delay": 2000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.aiChatbot}:create-embedding": {
"attempts": 3,
"backoff": {
"delay": 2000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.browserAutomation}:browser-session-cleanup": {
"attempts": 3,
"backoff": {
"delay": 10000,
"type": "fixed",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.browserAutomation}:browser-session-run": {
"attempts": 2,
"backoff": {
"delay": 5000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.browserAutomation}:usage-flush": {
"attempts": 3,
"backoff": {
"delay": 10000,
"type": "fixed",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.email}:deliver-webhook": {
"attempts": 5,
"backoff": {
"delay": 2000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.email}:send-transactional-email": {
"attempts": 3,
"backoff": {
"delay": 1000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.exports}:run-export": {
"attempts": 2,
"backoff": {
"delay": 10000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.filePreview}:generate-file-preview": {
"attempts": 3,
"backoff": {
"delay": 3000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.fileScan}:scan-file": {
"attempts": 3,
"backoff": {
"delay": 2000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.imports}:run-import": {
"attempts": 2,
"backoff": {
"delay": 10000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.maintenance}:run-cleanup": {
"attempts": 2,
"backoff": {
"delay": 5000,
"type": "fixed",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.notifications}:send-notification": {
"attempts": 3,
"backoff": {
"delay": 1000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
"${queueNames.pluginInvoke}:invoke-plugin": {
"attempts": 3,
"backoff": {
"delay": 2000,
"type": "exponential",
},
"removeOnComplete": true,
"removeOnFail": 1000,
},
}
`);
});
});
describe("queue idempotency diagnostics", () => {
test("uses an explicit jobId before an idempotencyKey", async () => {
const options = await enqueueOptionsFor(buildTransactionalMailJob({ to: ["user@example.com"], templateId: "welcome" }), {
idempotencyKey: "idempotency-key",
jobId: "explicit-job-id",
});
expect(options?.jobId).toBe("explicit-job-id");
expect(options).not.toHaveProperty("idempotencyKey");
});
test("uses an explicit idempotencyKey before payload metadata", async () => {
const options = await enqueueOptionsFor(
buildNotificationJob({
tenantId: "tenant_1",
userId: "user_1",
channel: "in-app",
messageKey: "message.ready",
metadata: { idempotencyKey: "metadata-key" },
}),
{ idempotencyKey: "explicit-idempotency-key" }
);
expect(options?.jobId).toBe("explicit-idempotency-key");
expect(options).not.toHaveProperty("idempotencyKey");
});
test("uses metadata idempotencyKey when no explicit key is present", async () => {
const options = await enqueueOptionsFor(
buildCleanupJob({ task: "temporary-files", metadata: { idempotencyKey: "metadata-key" } })
);
expect(options?.jobId).toBe("metadata-key");
});
test("does not derive jobId values from body payloads", async () => {
const options = await enqueueOptionsFor(
buildWebhookDeliveryJob({
url: "https://example.com/webhook",
eventName: "entity.created",
body: { idempotencyKey: "unsafe-body-key", jobId: "unsafe-body-job-id" },
})
);
expect(options).not.toHaveProperty("jobId");
});
});