Skip to content
This repository was archived by the owner on Sep 17, 2024. It is now read-only.

Commit c7a6789

Browse files
authored
chore: re-enable rate_limit module (#107)
1 parent 1e2a0ca commit c7a6789

File tree

4 files changed

+1385
-50
lines changed

4 files changed

+1385
-50
lines changed

modules/rate_limit/scripts/throttle.ts

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,56 +28,56 @@ export async function run(
2828
ctx: ScriptContext,
2929
req: Request,
3030
): Promise<Response> {
31-
// interface TokenBucket {
32-
// tokens: number;
33-
// lastRefill: Date;
34-
// }
35-
//
36-
// // Update the token bucket
37-
// //
38-
// // `TokenBucket` is an unlogged table which are significantly faster to
39-
// // write to than regular tables, but are not durable. This is important
40-
// // because this script will be called on every request.
41-
// const rows = await ctx.db.$queryRaw<TokenBucket[]>`
42-
// WITH updated_bucket AS (
43-
// UPDATE "TokenBuckets" b
44-
// SET
45-
// "tokens" = CASE
46-
// -- Reset the bucket and consume 1 token
47-
// WHEN now() > b."lastRefill" + make_interval(secs => ${req.period}) THEN ${
48-
// req.requests - 1
49-
// }
50-
// -- Consume 1 token
51-
// ELSE b.tokens - 1
52-
// END,
53-
// "lastRefill" = CASE
54-
// WHEN now() > b."lastRefill" + make_interval(secs => ${req.period}) THEN now()
55-
// ELSE b."lastRefill"
56-
// END
57-
// WHERE b."type" = ${req.type} AND b."key" = ${req.key}
58-
// RETURNING b."tokens", b."lastRefill"
59-
// ),
60-
// inserted AS (
61-
// INSERT INTO "TokenBuckets" ("type", "key", "tokens", "lastRefill")
62-
// SELECT ${req.type}, ${req.key}, ${req.requests - 1}, now()
63-
// WHERE NOT EXISTS (SELECT 1 FROM updated_bucket)
64-
// RETURNING "tokens", "lastRefill"
65-
// )
66-
// SELECT * FROM updated_bucket
67-
// UNION ALL
68-
// SELECT * FROM inserted;
69-
// `;
70-
// const { tokens, lastRefill } = rows[0];
31+
interface TokenBucket {
32+
tokens: number;
33+
lastRefill: Date;
34+
}
35+
36+
// Update the token bucket
7137
//
72-
// // If the bucket is empty, throw an error
73-
// if (tokens < 0) {
74-
// throw new RuntimeError("RATE_LIMIT_EXCEEDED", {
75-
// meta: {
76-
// retryAfter: new Date(lastRefill.getTime() + req.period * 1000)
77-
// .toUTCString(),
78-
// },
79-
// });
80-
// }
38+
// `TokenBucket` is an unlogged table which are significantly faster to
39+
// write to than regular tables, but are not durable. This is important
40+
// because this script will be called on every request.
41+
const rows = await ctx.db.$queryRaw<TokenBucket[]>`
42+
WITH updated_bucket AS (
43+
UPDATE "TokenBuckets" b
44+
SET
45+
"tokens" = CASE
46+
-- Reset the bucket and consume 1 token
47+
WHEN now() > b."lastRefill" + make_interval(secs => ${req.period}) THEN ${
48+
req.requests - 1
49+
}
50+
-- Consume 1 token
51+
ELSE b.tokens - 1
52+
END,
53+
"lastRefill" = CASE
54+
WHEN now() > b."lastRefill" + make_interval(secs => ${req.period}) THEN now()
55+
ELSE b."lastRefill"
56+
END
57+
WHERE b."type" = ${req.type} AND b."key" = ${req.key}
58+
RETURNING b."tokens", b."lastRefill"
59+
),
60+
inserted AS (
61+
INSERT INTO "TokenBuckets" ("type", "key", "tokens", "lastRefill")
62+
SELECT ${req.type}, ${req.key}, ${req.requests - 1}, now()
63+
WHERE NOT EXISTS (SELECT 1 FROM updated_bucket)
64+
RETURNING "tokens", "lastRefill"
65+
)
66+
SELECT * FROM updated_bucket
67+
UNION ALL
68+
SELECT * FROM inserted;
69+
`;
70+
const { tokens, lastRefill } = rows[0];
71+
72+
// If the bucket is empty, throw an error
73+
if (tokens < 0) {
74+
throw new RuntimeError("RATE_LIMIT_EXCEEDED", {
75+
meta: {
76+
retryAfter: new Date(lastRefill.getTime() + req.period * 1000)
77+
.toUTCString(),
78+
},
79+
});
80+
}
8181

8282
return {};
8383
}

0 commit comments

Comments
 (0)