Skip to content

Commit a5a1774

Browse files
committed
feat: add rate limit management service
Introduce the RateLimitSystem class to handle overriding and resetting queue rate limits. This service updates the database state and synchronizes the changes with the Redis cache to ensure runtime rate limiting policies are enforced correctly. Include unit tests to verify database interactions and side-effect calls to the queue service.
1 parent 3745b6d commit a5a1774

2 files changed

Lines changed: 123 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { PrismaClient, Prisma } from "@trigger.dev/database";
2+
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
3+
import { removeQueueRateLimits, updateQueueRateLimits } from "../runQueue.server";
4+
5+
export class RateLimitSystem {
6+
constructor(
7+
private prisma: PrismaClient
8+
) {}
9+
10+
async overrideQueueRateLimit(
11+
environment: AuthenticatedEnvironment,
12+
queueName: string,
13+
rateLimits: Array<{ limit: number; window: number }>
14+
) {
15+
const queue = await this.prisma.taskQueue.updateMany({
16+
where: {
17+
runtimeEnvironmentId: environment.id,
18+
name: queueName,
19+
},
20+
data: {
21+
rateLimit: rateLimits,
22+
},
23+
});
24+
25+
await updateQueueRateLimits(environment, queueName, rateLimits);
26+
}
27+
28+
async resetQueueRateLimit(environment: AuthenticatedEnvironment, queueName: string) {
29+
await this.prisma.taskQueue.updateMany({
30+
where: {
31+
runtimeEnvironmentId: environment.id,
32+
name: queueName,
33+
},
34+
data: {
35+
rateLimit: Prisma.DbNull,
36+
},
37+
});
38+
39+
await removeQueueRateLimits(environment, queueName);
40+
}
41+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { describe, it, expect, vi, beforeEach } from "vitest";
2+
import { RateLimitSystem } from "../app/v3/services/rateLimitSystem.server";
3+
import { PrismaClient, Prisma } from "@trigger.dev/database";
4+
import { Redis } from "ioredis";
5+
import { AuthenticatedEnvironment } from "../app/services/apiAuth.server";
6+
import * as runQueueServer from "../app/v3/runQueue.server";
7+
8+
vi.mock("../app/v3/runQueue.server", () => ({
9+
updateQueueRateLimits: vi.fn(),
10+
removeQueueRateLimits: vi.fn(),
11+
}));
12+
13+
describe("RateLimitSystem", () => {
14+
let prismaMock: any;
15+
let redisMock: any;
16+
let rateLimitSystem: RateLimitSystem;
17+
let mockEnvironment: AuthenticatedEnvironment;
18+
19+
beforeEach(() => {
20+
prismaMock = {
21+
taskQueue: {
22+
updateMany: vi.fn().mockResolvedValue({ count: 1 }),
23+
},
24+
};
25+
26+
rateLimitSystem = new RateLimitSystem(prismaMock as unknown as PrismaClient);
27+
28+
mockEnvironment = {
29+
id: "env-123",
30+
} as AuthenticatedEnvironment;
31+
32+
vi.clearAllMocks();
33+
});
34+
35+
describe("overrideQueueRateLimit", () => {
36+
it("should update the rateLimit field in the database and call the Redis sync method", async () => {
37+
const queueName = "test-queue";
38+
const rateLimits = [{ limit: 10, window: 60 }];
39+
40+
await rateLimitSystem.overrideQueueRateLimit(mockEnvironment, queueName, rateLimits);
41+
42+
expect(prismaMock.taskQueue.updateMany).toHaveBeenCalledWith({
43+
where: {
44+
runtimeEnvironmentId: mockEnvironment.id,
45+
name: queueName,
46+
},
47+
data: {
48+
rateLimit: rateLimits,
49+
},
50+
});
51+
52+
expect(runQueueServer.updateQueueRateLimits).toHaveBeenCalledWith(
53+
mockEnvironment,
54+
queueName,
55+
rateLimits
56+
);
57+
});
58+
});
59+
60+
describe("resetQueueRateLimit", () => {
61+
it("should clear the rateLimit field in the database and call the Redis sync method", async () => {
62+
const queueName = "test-queue";
63+
64+
await rateLimitSystem.resetQueueRateLimit(mockEnvironment, queueName);
65+
66+
expect(prismaMock.taskQueue.updateMany).toHaveBeenCalledWith({
67+
where: {
68+
runtimeEnvironmentId: mockEnvironment.id,
69+
name: queueName,
70+
},
71+
data: {
72+
rateLimit: Prisma.DbNull,
73+
},
74+
});
75+
76+
expect(runQueueServer.removeQueueRateLimits).toHaveBeenCalledWith(
77+
mockEnvironment,
78+
queueName
79+
);
80+
});
81+
});
82+
});

0 commit comments

Comments
 (0)