Skip to content

Commit 4b4e538

Browse files
committed
feat: Implement rate limit waiting instead of erroring
1 parent d496474 commit 4b4e538

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

src/lib/rate-limit.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { sleep } from "bun"
12
import consola from "consola"
23

34
import type { State } from "./state"
45

56
import { HTTPError } from "./http-error"
67

7-
export function checkRateLimit(state: State) {
8+
export async function checkRateLimit(state: State) {
89
if (state.rateLimitSeconds === undefined) return
910

1011
const now = Date.now()
@@ -21,10 +22,22 @@ export function checkRateLimit(state: State) {
2122
return
2223
}
2324

24-
const waitTimeSeconds = Math.round(state.rateLimitSeconds - elapsedSeconds)
25+
const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)
26+
27+
if (!state.rateLimitWait) {
28+
consola.warn(
29+
`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,
30+
)
31+
throw new HTTPError("Rate limit exceeded", Response.json({ status: 429 }))
32+
}
33+
34+
const waitTimeMs = waitTimeSeconds * 1000
2535
consola.warn(
26-
`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,
36+
`Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,
2737
)
28-
29-
throw new HTTPError("Rate limit exceeded", Response.json({ status: 429 }))
38+
await sleep(waitTimeMs)
39+
// eslint-disable-next-line require-atomic-updates
40+
state.lastRequestTimestamp = now
41+
consola.info("Rate limit wait completed, proceeding with request")
42+
return
3043
}

src/lib/state.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface State {
99
vsCodeVersion?: string
1010

1111
manualApprove: boolean
12+
rateLimitWait: boolean
1213

1314
// Rate limiting configuration
1415
rateLimitSeconds?: number
@@ -18,4 +19,5 @@ export interface State {
1819
export const state: State = {
1920
accountType: "individual",
2021
manualApprove: false,
22+
rateLimitWait: false,
2123
}

src/main.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface RunServerOptions {
1717
business: boolean
1818
manual: boolean
1919
rateLimit: number | undefined
20+
rateLimitWait: boolean
2021
}
2122

2223
export async function runServer(options: RunServerOptions): Promise<void> {
@@ -32,6 +33,7 @@ export async function runServer(options: RunServerOptions): Promise<void> {
3233

3334
state.manualApprove = options.manual
3435
state.rateLimitSeconds = options.rateLimit
36+
state.rateLimitWait = options.rateLimitWait
3537

3638
await ensurePaths()
3739
await cacheVSCodeVersion()
@@ -77,6 +79,13 @@ const main = defineCommand({
7779
type: "string",
7880
description: "Rate limit in seconds between requests",
7981
},
82+
wait: {
83+
alias: "w",
84+
type: "boolean",
85+
default: false,
86+
description:
87+
"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set",
88+
},
8089
},
8190
run({ args }) {
8291
const rateLimitRaw = args["rate-limit"]
@@ -85,14 +94,14 @@ const main = defineCommand({
8594
rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)
8695

8796
const port = Number.parseInt(args.port, 10)
88-
// const rateLimit = Number.parseInt(args["rate-limit"], 10)
8997

9098
return runServer({
9199
port,
92100
verbose: args.verbose,
93101
business: args.business,
94102
manual: args.manual,
95103
rateLimit,
104+
rateLimitWait: Boolean(args["rate-limit-wait"]),
96105
})
97106
},
98107
})

src/routes/chat-completions/handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from "~/services/copilot/create-chat-completions"
1616

1717
export async function handleCompletion(c: Context) {
18-
checkRateLimit(state)
18+
await checkRateLimit(state)
1919

2020
let payload = await c.req.json<ChatCompletionsPayload>()
2121

0 commit comments

Comments
 (0)