2
2
* Sched's API has a rate limit of 30 requests per minute.
3
3
*/
4
4
5
- let last429Timestamp : number | null = null
6
- const RATE_LIMIT_MS = 60_000
5
+ let rateLimitResetAt : number | null = null
7
6
8
7
type RequestURL = string
9
8
type RequestPending = Promise < unknown >
@@ -17,8 +16,8 @@ const requestsRetried = new Map<
17
16
18
17
export async function fetchData < T > ( url : string ) : Promise < T > {
19
18
try {
20
- if ( last429Timestamp && Date . now ( ) - last429Timestamp < RATE_LIMIT_MS ) {
21
- const wait = RATE_LIMIT_MS - ( Date . now ( ) - last429Timestamp )
19
+ if ( rateLimitResetAt && Date . now ( ) < rateLimitResetAt ) {
20
+ const wait = rateLimitResetAt - Date . now ( )
22
21
await new Promise ( resolve => setTimeout ( resolve , wait ) )
23
22
}
24
23
@@ -34,31 +33,40 @@ export async function fetchData<T>(url: string): Promise<T> {
34
33
// Take note that this is feasible only because
35
34
// we're currently only using this API at build time.
36
35
if ( response . status === 429 ) {
37
- last429Timestamp = Date . now ( )
36
+ let wait = 60_000
37
+ const xRateLimitResetAt = response . headers . get ( "x-rate-limit-reset-at" )
38
+ if ( xRateLimitResetAt ) {
39
+ rateLimitResetAt = Number ( xRateLimitResetAt ) * 1000
40
+ console . warn (
41
+ `Rate limit reset at ${ new Date ( rateLimitResetAt ) . toISOString ( ) } ` ,
42
+ )
43
+ wait = rateLimitResetAt - Date . now ( )
44
+ }
38
45
39
46
const later = Promise . withResolvers < T > ( )
40
47
requestsRetried . set ( url , later . promise )
41
48
const queueSize = requestsRetried . size
42
49
43
50
console . warn (
44
- `Rate limit exceeded, retrying in 60 seconds : ${ url } (queue size: ${ queueSize } )` ,
51
+ `Rate limit exceeded, retrying in ${ Math . round ( wait / 1000 ) } s : ${ url } (queue size: ${ queueSize } )` ,
45
52
)
46
53
47
54
const size = Object . entries ( requestsRetried ) . filter (
48
55
( [ _ , status ] ) => status instanceof Promise ,
49
56
) . length
50
57
51
58
console . warn ( `${ size } requests retrying...` )
59
+
52
60
setTimeout (
53
61
( ) =>
54
62
later . resolve (
55
63
fetchData < T > ( url ) . then ( data => {
64
+ rateLimitResetAt = null
56
65
requestsRetried . set ( url , "ok" )
57
- last429Timestamp = null
58
66
return data
59
67
} ) ,
60
68
) ,
61
- 60_000 ,
69
+ wait ,
62
70
)
63
71
64
72
return later . promise
0 commit comments