feat(tasks): implement long-term delayed tasks with KV and Cron
This commit is contained in:
123
src/libs/tasks/delayedTask.spec.ts
Normal file
123
src/libs/tasks/delayedTask.spec.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
import { beforeEach, describe, expect, it, mock } from "bun:test";
|
||||
|
||||
import type { DelayedTaskMetadata } from "./delayedTask";
|
||||
import {
|
||||
deserializeDelayedTask,
|
||||
generateTaskKey,
|
||||
serializeDelayedTask,
|
||||
} from "./delayedTask";
|
||||
|
||||
describe("delayedTask", () => {
|
||||
describe("generateTaskKey", () => {
|
||||
it("generates key with correct format", () => {
|
||||
const scheduledTime = 1732896000;
|
||||
const taskId = "abc-123-def";
|
||||
|
||||
const key = generateTaskKey(scheduledTime, taskId);
|
||||
|
||||
expect(key).toBe("delayed-task:1732896000:abc-123-def");
|
||||
});
|
||||
|
||||
it("generates unique keys for different timestamps", () => {
|
||||
const taskId = "same-id";
|
||||
const key1 = generateTaskKey(1000, taskId);
|
||||
const key2 = generateTaskKey(2000, taskId);
|
||||
|
||||
expect(key1).not.toBe(key2);
|
||||
});
|
||||
|
||||
it("generates unique keys for different task IDs", () => {
|
||||
const timestamp = 1000;
|
||||
const key1 = generateTaskKey(timestamp, "id-1");
|
||||
const key2 = generateTaskKey(timestamp, "id-2");
|
||||
|
||||
expect(key1).not.toBe(key2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("serializeDelayedTask & deserializeDelayedTask", () => {
|
||||
let testMetadata: DelayedTaskMetadata;
|
||||
|
||||
beforeEach(() => {
|
||||
testMetadata = {
|
||||
queueName: "NEW_EPISODE",
|
||||
body: { aniListId: 12345, episodeNumber: 1 },
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Anilist-Token": "test-token",
|
||||
},
|
||||
scheduledEpochTime: 1732896000,
|
||||
taskId: "test-task-id",
|
||||
createdAt: 1732800000,
|
||||
retryCount: 0,
|
||||
};
|
||||
});
|
||||
|
||||
it("serializes metadata to JSON string", () => {
|
||||
const serialized = serializeDelayedTask(testMetadata);
|
||||
|
||||
expect(serialized).toBeTypeOf("string");
|
||||
expect(() => JSON.parse(serialized)).not.toThrow();
|
||||
});
|
||||
|
||||
it("deserializes JSON string back to metadata", () => {
|
||||
const serialized = serializeDelayedTask(testMetadata);
|
||||
const deserialized = deserializeDelayedTask(serialized);
|
||||
|
||||
expect(deserialized).toEqual(testMetadata);
|
||||
});
|
||||
|
||||
it("preserves all metadata fields", () => {
|
||||
const serialized = serializeDelayedTask(testMetadata);
|
||||
const deserialized = deserializeDelayedTask(serialized);
|
||||
|
||||
expect(deserialized.queueName).toBe("NEW_EPISODE");
|
||||
expect(deserialized.body).toEqual({ aniListId: 12345, episodeNumber: 1 });
|
||||
expect(deserialized.headers).toEqual({
|
||||
"Content-Type": "application/json",
|
||||
"X-Anilist-Token": "test-token",
|
||||
});
|
||||
expect(deserialized.scheduledEpochTime).toBe(1732896000);
|
||||
expect(deserialized.taskId).toBe("test-task-id");
|
||||
expect(deserialized.createdAt).toBe(1732800000);
|
||||
expect(deserialized.retryCount).toBe(0);
|
||||
});
|
||||
|
||||
it("handles metadata without retryCount", () => {
|
||||
delete testMetadata.retryCount;
|
||||
const serialized = serializeDelayedTask(testMetadata);
|
||||
const deserialized = deserializeDelayedTask(serialized);
|
||||
|
||||
expect(deserialized.retryCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it("handles ANILIST_UPDATES queue body", () => {
|
||||
const anilistMetadata: DelayedTaskMetadata = {
|
||||
queueName: "ANILIST_UPDATES",
|
||||
body: {
|
||||
deviceId: "device-123",
|
||||
watchStatus: null,
|
||||
titleId: 456,
|
||||
updateType: 0,
|
||||
},
|
||||
headers: { "Content-Type": "application/json" },
|
||||
scheduledEpochTime: 1732896000,
|
||||
taskId: "test-id",
|
||||
createdAt: 1732800000,
|
||||
};
|
||||
|
||||
const serialized = serializeDelayedTask(anilistMetadata);
|
||||
const deserialized = deserializeDelayedTask(serialized);
|
||||
|
||||
expect(deserialized.queueName).toBe("ANILIST_UPDATES");
|
||||
expect(deserialized.body).toEqual({
|
||||
deviceId: "device-123",
|
||||
watchStatus: null,
|
||||
titleId: 456,
|
||||
updateType: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user