{
"$type": "site.standard.document",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Motivation"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"features": [
{
"$type": "pub.leaflet.richtext.facet#link",
"uri": "https://mapvoyage.app"
}
],
"index": {
"byteEnd": 53,
"byteStart": 44
}
}
],
"plaintext": "Why would I do this? For my latest project, mapvoyage, I need to serve text files (wikitext to be specific), directly to the user if possible, as well as in a separate function select one wikitext file to display from a list of wikidata ids that may or may not have an associated wikitext file. Latency is important and I'd like the data to be edge-available if possible. R2 with workers seemed ideal here, as the client can download the files from R2 directly and I can lookup the urls from a separate worker, which hopefully shouldn't have a long latency for reading them."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "The Benchmark"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Luckily this was simple enough that ChatGPT could generate a simple script. I could upload this Cloudflare Workers via the dashboard directly and only needed to connect it to the R2 bucket. The files are just the single character 1 to 5. 4.txt is excluded as it didn't upload for some reason."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "javascript",
"plaintext": "export default {\n async fetch(request, env) {\n // Define the list of object keys to test.\n const keys = [\"1.txt\", \"2.txt\", \"3.txt\", \"5.txt\"];\n \n // Start all HEAD requests in parallel and measure each one's latency.\n const promises = keys.map(async (key) => {\n const start = performance.now();\n const headResponse = await env.MY_R2_BUCKET.head(key);\n const end = performance.now();\n const latency = end - start;\n return { key, latency, found: !!headResponse };\n });\n \n const results = await Promise.all(promises);\n \n // Filter only successful responses.\n const successful = results.filter(result => result.found);\n const maxLatency = successful.length > 0\n ? Math.max(...successful.map(r => r.latency))\n : 0;\n \n // Build a report with each key's latency and the maximum.\n const output = results.map(r =>\n `Key: ${r.key} - ${r.found ? r.latency.toFixed(2) + \" ms\" : \"Not Found\"}`\n ).join(\"\\n\") +\n `\\nMaximum latency: ${maxLatency.toFixed(2)} ms`;\n \n return new Response(output, { status: 200 });\n }\n};\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "The Results"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "The region of the bucket is Eastern Europe, for a worker called from Europe I got the following responses:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Uncached"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "Key: 1.txt - 379.00 ms\nKey: 2.txt - 383.00 ms\nKey: 3.txt - 375.00 ms\nKey: 5.txt - 663.00 ms\nMaximum latency: 663.00 ms"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Cached"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "Key: 1.txt - 52.00 ms\nKey: 2.txt - 47.00 ms\nKey: 3.txt - 48.00 ms\nKey: 5.txt - 54.00 ms\nMaximum latency: 54.00 ms"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": ""
}
}
],
"id": "019e6e7e-c72c-7115-89a2-6709a5312449"
}
]
},
"description": "",
"path": "/3mmvzq53xc22s",
"publishedAt": "2025-03-09T13:32:00.000Z",
"site": "at://did:plc:z4yzhhsdetqfkq6hneiwc3cv/site.standard.publication/3m5k5jw2onk2h",
"tags": [
"performance",
"deployments",
"cloudflare",
"mapvoyage"
],
"title": "Benchmarking Cloudflare R2 HEAD Requests from Cloudflare Workers"
}