Skip to content

Commit 2bb3db4

Browse files
committed
Separate /engine/ rate limiter
1 parent c63915f commit 2bb3db4

File tree

5 files changed

+53
-3
lines changed

5 files changed

+53
-3
lines changed

apps/webapp/app/entry.server.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ const sqsEventConsumer = singleton("sqsEventConsumer", getSharedSqsEventConsumer
208208
singleton("RunEngineEventBusHandlers", registerRunEngineEventBusHandlers);
209209

210210
export { apiRateLimiter } from "./services/apiRateLimit.server";
211+
export { engineRateLimiter } from "./services/engineRateLimit.server";
211212
export { socketIo } from "./v3/handleSocketIo.server";
212213
export { wss } from "./v3/handleWebsockets.server";
213214
export { registryProxy } from "./v3/registryProxy.server";

apps/webapp/app/env.server.ts

+16
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,22 @@ const EnvironmentSchema = z.object({
506506
.string()
507507
.default(process.env.REDIS_TLS_DISABLED ?? "false"),
508508

509+
//API Rate limiting
510+
/**
511+
* @example "60s"
512+
* @example "1m"
513+
* @example "1h"
514+
* @example "1d"
515+
* @example "1000ms"
516+
* @example "1000s"
517+
*/
518+
RUN_ENGINE_RATE_LIMIT_REFILL_INTERVAL: z.string().default("10s"), // refill 250 tokens every 10 seconds
519+
RUN_ENGINE_RATE_LIMIT_MAX: z.coerce.number().int().default(1200), // allow bursts of 750 requests
520+
RUN_ENGINE_RATE_LIMIT_REFILL_RATE: z.coerce.number().int().default(400), // refix 250 tokens every 10 seconds
521+
RUN_ENGINE_RATE_LIMIT_REQUEST_LOGS_ENABLED: z.string().default("0"),
522+
RUN_ENGINE_RATE_LIMIT_REJECTION_LOGS_ENABLED: z.string().default("1"),
523+
RUN_ENGINE_RATE_LIMIT_LIMITER_LOGS_ENABLED: z.string().default("0"),
524+
509525
/** How long should the presence ttl last */
510526
DEV_PRESENCE_TTL_MS: z.coerce.number().int().default(30_000),
511527
DEV_PRESENCE_POLL_INTERVAL_MS: z.coerce.number().int().default(5_000),

apps/webapp/app/services/apiRateLimit.server.ts

-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@ export const apiRateLimiter = authorizationRateLimitMiddleware({
5959
"/api/v1/usage/ingest",
6060
"/api/v1/auth/jwt/claims",
6161
/^\/api\/v1\/runs\/[^\/]+\/attempts$/, // /api/v1/runs/$runFriendlyId/attempts
62-
// run engine DEV endpoints
63-
"/api/v1/dev/dequeue",
64-
"/api/v1/dev/presence",
6562
],
6663
log: {
6764
rejections: env.API_RATE_LIMIT_REJECTION_LOGS_ENABLED === "1",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { env } from "~/env.server";
2+
import { authenticateAuthorizationHeader } from "./apiAuth.server";
3+
import { authorizationRateLimitMiddleware } from "./authorizationRateLimitMiddleware.server";
4+
import { Duration } from "./rateLimiter.server";
5+
6+
export const engineRateLimiter = authorizationRateLimitMiddleware({
7+
redis: {
8+
port: env.RATE_LIMIT_REDIS_PORT,
9+
host: env.RATE_LIMIT_REDIS_HOST,
10+
username: env.RATE_LIMIT_REDIS_USERNAME,
11+
password: env.RATE_LIMIT_REDIS_PASSWORD,
12+
tlsDisabled: env.RATE_LIMIT_REDIS_TLS_DISABLED === "true",
13+
clusterMode: env.RATE_LIMIT_REDIS_CLUSTER_MODE_ENABLED === "1",
14+
},
15+
keyPrefix: "engine",
16+
defaultLimiter: {
17+
type: "tokenBucket",
18+
refillRate: env.RUN_ENGINE_RATE_LIMIT_REFILL_RATE,
19+
interval: env.RUN_ENGINE_RATE_LIMIT_REFILL_INTERVAL as Duration,
20+
maxTokens: env.RUN_ENGINE_RATE_LIMIT_MAX,
21+
},
22+
limiterCache: {
23+
fresh: 60_000 * 10, // Data is fresh for 10 minutes
24+
stale: 60_000 * 20, // Date is stale after 20 minutes
25+
},
26+
pathMatchers: [/^\/engine/],
27+
// Allow /api/v1/tasks/:id/callback/:secret
28+
pathWhiteList: [],
29+
log: {
30+
rejections: env.RUN_ENGINE_RATE_LIMIT_REJECTION_LOGS_ENABLED === "1",
31+
requests: env.RUN_ENGINE_RATE_LIMIT_REQUEST_LOGS_ENABLED === "1",
32+
limiter: env.RUN_ENGINE_RATE_LIMIT_LIMITER_LOGS_ENABLED === "1",
33+
},
34+
});

apps/webapp/server.ts

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ if (process.env.HTTP_SERVER_DISABLED !== "true") {
4343
const wss: WebSocketServer | undefined = build.entry.module.wss;
4444
const registryProxy: RegistryProxy | undefined = build.entry.module.registryProxy;
4545
const apiRateLimiter: RateLimitMiddleware = build.entry.module.apiRateLimiter;
46+
const engineRateLimiter: RateLimitMiddleware = build.entry.module.engineRateLimiter;
4647
const runWithHttpContext: RunWithHttpContextFunction = build.entry.module.runWithHttpContext;
4748

4849
if (registryProxy && process.env.ENABLE_REGISTRY_PROXY === "true") {
@@ -95,6 +96,7 @@ if (process.env.HTTP_SERVER_DISABLED !== "true") {
9596
}
9697

9798
app.use(apiRateLimiter);
99+
app.use(engineRateLimiter);
98100

99101
app.all(
100102
"*",

0 commit comments

Comments
 (0)