Skip to content

Commit 56c3a7c

Browse files
committed
Use monotonic clock for rate limiting
1 parent 13534cc commit 56c3a7c

File tree

2 files changed

+10
-10
lines changed

2 files changed

+10
-10
lines changed

src/core/task/Task.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,7 +2036,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
20362036

20372037
const drainStreamInBackgroundToFindAllUsage = async (apiReqIndex: number) => {
20382038
const timeoutMs = DEFAULT_USAGE_COLLECTION_TIMEOUT_MS
2039-
const startTime = Date.now()
2039+
const startTime = performance.now()
20402040
const modelId = getModelId(this.apiConfiguration)
20412041

20422042
// Local variables to accumulate usage data without affecting the main flow
@@ -2107,7 +2107,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
21072107
// Use the same iterator that the main loop was using
21082108
while (!item.done) {
21092109
// Check for timeout
2110-
if (Date.now() - startTime > timeoutMs) {
2110+
if (performance.now() - startTime > timeoutMs) {
21112111
console.warn(
21122112
`[Background Usage Collection] Timed out after ${timeoutMs}ms for model: ${modelId}, processed ${chunkCount} chunks`,
21132113
)
@@ -2559,10 +2559,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
25592559
// Use the shared timestamp so that subtasks respect the same rate-limit
25602560
// window as their parent tasks.
25612561
if (Task.lastGlobalApiRequestTime) {
2562-
const now = Date.now()
2562+
const now = performance.now()
25632563
const timeSinceLastRequest = now - Task.lastGlobalApiRequestTime
25642564
const rateLimit = apiConfiguration?.rateLimitSeconds || 0
2565-
rateLimitDelay = Math.ceil(Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000)
2565+
rateLimitDelay = Math.ceil(Math.min(rateLimit, Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000))
25662566
}
25672567

25682568
// Only show rate limiting message if we're not retrying. If retrying, we'll include the delay there.
@@ -2577,7 +2577,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
25772577

25782578
// Update last request time before making the request so that subsequent
25792579
// requests — even from new subtasks — will honour the provider's rate-limit.
2580-
Task.lastGlobalApiRequestTime = Date.now()
2580+
Task.lastGlobalApiRequestTime = performance.now()
25812581

25822582
const systemPrompt = await this.getSystemPrompt()
25832583
this.lastUsedInstructions = systemPrompt

src/core/task/__tests__/Task.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,9 +1098,9 @@ describe("Cline", () => {
10981098
await parentIterator.next()
10991099

11001100
// Simulate time passing (more than rate limit)
1101-
const originalDateNow = Date.now
1102-
const mockTime = Date.now() + (mockApiConfig.rateLimitSeconds + 1) * 1000
1103-
Date.now = vi.fn(() => mockTime)
1101+
const originalPerformanceNow = performance.now
1102+
const mockTime = performance.now() + (mockApiConfig.rateLimitSeconds + 1) * 1000
1103+
performance.now = vi.fn(() => mockTime)
11041104

11051105
// Create a subtask after time has passed
11061106
const child = new Task({
@@ -1121,8 +1121,8 @@ describe("Cline", () => {
11211121
// Verify no rate limiting was applied
11221122
expect(mockDelay).not.toHaveBeenCalled()
11231123

1124-
// Restore Date.now
1125-
Date.now = originalDateNow
1124+
// Restore performance.now
1125+
performance.now = originalPerformanceNow
11261126
})
11271127

11281128
it("should share rate limiting across multiple subtasks", async () => {

0 commit comments

Comments
 (0)