Skip to content

Commit 29485be

Browse files
committed
thomasgauvin: add limit writes per second
1 parent 54daeee commit 29485be

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

src/content/docs/kv/api/write-key-value-pairs.mdx

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,136 @@ await env.NAMESPACE.put(key, value, {
136136
});
137137
```
138138
139+
### Limits to KV writes to the same key
140+
141+
Workers KV has a maximum of 1 write to the same key per second. Writes made to the same key within 1 second will cause errors to be thrown.
142+
143+
The following example serves only as a demonstration of how multiple writes to the same key may return errors by forcing concurrent writes within a single Worker invocation. This is not a pattern that should be used in production.
144+
145+
```typescript
146+
export default {
147+
async fetch(request, env, ctx): Promise<Response> {
148+
// Rest of code omitted
149+
const key = "common-key";
150+
const parallelWritesCount = 20;
151+
152+
// Helper function to attempt a write to KV and handle errors
153+
const attemptWrite = async (i: number) => {
154+
try {
155+
await env.simple_kv_hono_jsx.put(key, `Write attempt #${i}`);
156+
return { attempt: i, success: true };
157+
} catch (error) {
158+
// An error may be thrown if a write to the same key is made within 1 second with a message. For example:
159+
// error: {
160+
// "message": "KV PUT failed: 429 Too Many Requests"
161+
// }
162+
163+
return {
164+
attempt: i,
165+
success: false,
166+
error: { message: (error as Error).message },
167+
};
168+
}
169+
};
170+
171+
// Send all requests in parallel and collect results
172+
const results = await Promise.all(
173+
Array.from({ length: parallelWritesCount }, (_, i) =>
174+
attemptWrite(i + 1),
175+
),
176+
);
177+
// Results will look like:
178+
// [
179+
// {
180+
// "attempt": 1,
181+
// "success": true
182+
// },
183+
// {
184+
// "attempt": 2,
185+
// "success": false,
186+
// "error": {
187+
// "message": "KV PUT failed: 429 Too Many Requests"
188+
// }
189+
// },
190+
// ...
191+
// ]
192+
193+
return new Response(JSON.stringify(results), {
194+
headers: { "Content-Type": "application/json" },
195+
});
196+
},
197+
};
198+
```
199+
200+
To handle these errors, we recommend implementing a retry logic, with exponential backoff. Here is a simple approach to add retries to the above code.
201+
202+
```typescript
203+
export default {
204+
async fetch(request, env, ctx): Promise<Response> {
205+
// Rest of code omitted
206+
const key = "common-key";
207+
const parallelWritesCount = 20;
208+
209+
// Helper function to attempt a write to KV with retries
210+
const attemptWrite = async (i: number) => {
211+
return await retryWithBackoff(async () => {
212+
await env.simple_kv_hono_jsx.put(key, `Write attempt #${i}`);
213+
return { attempt: i, success: true };
214+
});
215+
};
216+
217+
// Send all requests in parallel and collect results
218+
const results = await Promise.all(
219+
Array.from({ length: parallelWritesCount }, (_, i) =>
220+
attemptWrite(i + 1),
221+
),
222+
);
223+
224+
return new Response(JSON.stringify(results), {
225+
headers: { "Content-Type": "application/json" },
226+
});
227+
},
228+
};
229+
230+
async function retryWithBackoff(
231+
fn: Function,
232+
maxAttempts = 5,
233+
initialDelay = 1000,
234+
) {
235+
let attempts = 0;
236+
let delay = initialDelay;
237+
238+
while (attempts < maxAttempts) {
239+
try {
240+
// Attempt the function
241+
return await fn();
242+
} catch (error) {
243+
// Check if the error is a rate limit error
244+
if (
245+
(error as Error).message.includes(
246+
"KV PUT failed: 429 Too Many Requests",
247+
)
248+
) {
249+
attempts++;
250+
if (attempts >= maxAttempts) {
251+
throw new Error("Max retry attempts reached");
252+
}
253+
254+
// Wait for the backoff period
255+
console.warn(`Attempt ${attempts} failed. Retrying in ${delay} ms...`);
256+
await new Promise((resolve) => setTimeout(resolve, delay));
257+
258+
// Exponential backoff
259+
delay *= 2;
260+
} else {
261+
// If it's a different error, rethrow it
262+
throw error;
263+
}
264+
}
265+
}
266+
}
267+
```
268+
139269
## Other methods to access KV
140270
141271
You can also [write key-value pairs from the command line with Wrangler](/kv/reference/kv-commands/#create) and [write data via the API](/api/operations/workers-kv-namespace-write-key-value-pair-with-metadata).

0 commit comments

Comments
 (0)