{
  "$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"
}