{
"path": "/3lzrjubkqck2k",
"site": "at://did:plc:57od6g2ic3e3b3kauctjmo3k/site.standard.publication/3lwagtcm36s2d",
"$type": "site.standard.document",
"title": "Sliding Window Rate Limiting with Deno KV",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.blockquote",
"facets": [
{
"index": {
"byteEnd": 57,
"byteStart": 50
},
"features": [
{
"uri": "https://omg.lol",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 200,
"byteStart": 181
},
"features": [
{
"uri": "https://cistern.app",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "The following post was originally published on my omg.lol Weblog on February 7th, 2024. The app that it refers to as Fissure is now known as Cistern, and a WIP version is usable at https://cistern.app. I've corrected a couple typos and tweaked the code example, which was bugged 🤪"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I'm building out an ingestion API for Obsidian called Fissure, and since I want to offer it for free to a small extent, I was looking into adding a rate limiter to reduce abuse. I'm deploying on Deno Deploy, and my storage backend is Deno KV, so I felt that a sliding window rate limiter was a good choice."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "There are more detailed articles on the subject, but to my understanding the algorithm works something like this:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Define a fixed interval of time as the window period—e.g. 1 hour, 1 day"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "When a request comes in, get the number of requests made in the current period and the previous period"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.blockquote",
"facets": [],
"plaintext": "If the time is 3:45pm and your window period is 1 hour, get the number of requests made between 2–3pm and 3–4pm."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 48,
"byteStart": 40
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "Calculate the percentage overlap of the previous period with the current sliding window"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.blockquote",
"facets": [],
"plaintext": "If, again, the time is 3:45pm and your window period is 1 hour, your current window is 2:45pm–3:45pm—from an hour ago until the current moment. Therefore, the percentage overlap of the previous period with the current window is 0.25, or 25%."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 85,
"byteStart": 84
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "With all that information, use the following equation to get the number of requests n with the following values:"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 1,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "x is the number of requests made in current period"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 1,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 43,
"byteStart": 35
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "y is the number of requests in the previous period"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 1,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "z is the percentage overlap of the previous period with the current window"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "n = x + y * z",
"syntaxHighlightingTheme": "rose-pine"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 4,
"byteStart": 3
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "If n is greater than or equal to your maximum number of periodic requests, drop it. Here's roughly the implementation that I settled on:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "typescript",
"plaintext": "import { eachHourOfInterval, subHours } from 'npm:date-fns'\n\nconst kv = await Deno.openKv()\nconst MAXIMUM_HOURLY_REQUESTS = 50\nconst HOUR_IN_MILLISECONDS = 3_600_000\n\nasync function shouldDropRequest(userId: string): Promise<boolean> {\n const windowEnd = new Date();\n const windowStart = subHours(windowEnd, 1);\n const [lastHour, currentHour] = eachHourOfInterval({\n start: windowStart,\n end: windowEnd,\n });\n const [lastPeriod, currentPeriod] = await kv.getMany<\n [Deno.KvU64, Deno.KvU64]\n >([\n [\"user\", userId, \"period\", lastHour.getTime().toString()],\n [\"user\", userId, \"period\", currentHour.getTime().toString()],\n ]);\n\n const currentRequests = Number(currentPeriod.value?.value ?? 0n);\n const previousRequests = Number(lastPeriod.value?.value ?? 0n);\n const previousWeight = (currentHour.getTime() - windowStart.getTime()) /\n 3_600_000;\n\n if (currentPeriod.value === null) {\n await kv.atomic()\n .set(currentPeriod.key, new Deno.KvU64(1n), {\n expireIn: HOUR_IN_MILLISECONDS * 2,\n })\n .commit();\n } else {\n await kv.atomic()\n .sum(currentPeriod.key, 1n)\n .commit();\n }\n\n return Math.floor(currentRequests + (previousRequests * previousWeight)) >=\n MAXIMUM_HOURLY_REQUESTS\n}",
"syntaxHighlightingTheme": "rose-pine"
}
}
]
}
]
},
"bskyPostRef": {
"cid": "bafyreiauf4ydtelvuz2zlpud44oj3b4mf7pzq3rqxuoyvl6awp4l2bsdgi",
"uri": "at://did:plc:57od6g2ic3e3b3kauctjmo3k/app.bsky.feed.post/3lzrjufzwdk2k",
"commit": {
"cid": "bafyreidmcfba22h7x5cd6j72t26x7gcwjtzyojb2kl3sijll3iw4isqoyu",
"rev": "3lzrjug4ckn2q"
},
"validationStatus": "valid"
},
"description": "If you have a KV cache, why not use it?",
"publishedAt": "2025-09-26T22:39:13.226Z"
}