
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sat, 04 Apr 2026 11:27:17 GMT</lastBuildDate>
        <item>
            <title><![CDATA[How Workers VPC Services connects to your regional private networks from anywhere in the world]]></title>
            <link>https://blog.cloudflare.com/workers-vpc-open-beta/</link>
            <pubDate>Wed, 05 Nov 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Workers VPC Services enter open beta today. We look under the hood to see how Workers VPC connects your globally-deployed Workers to your regional private networks by using Cloudflare's global network, while abstracting cross-cloud networking complexity. ]]></description>
            <content:encoded><![CDATA[ <p>In April, we shared our vision for a <a href="https://blog.cloudflare.com/workers-virtual-private-cloud/"><u>global virtual private cloud on Cloudflare</u></a>, a way to unlock your applications from regionally constrained clouds and on-premise networks, enabling you to build truly cross-cloud applications.</p><p>Today, we’re announcing the first milestone of our Workers VPC initiative: VPC Services. VPC Services allow you to connect to your APIs, containers, virtual machines, serverless functions, databases and other services in regional private networks via <a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/"><u>Cloudflare Tunnels</u></a> from your <a href="https://workers.cloudflare.com/"><u>Workers</u></a> running anywhere in the world. </p><p>Once you set up a Tunnel in your desired network, you can register each service that you want to expose to Workers by configuring its host or IP address. Then, you can access the VPC Service as you would any other <a href="https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/"><u>Workers service binding</u></a> — Cloudflare’s network will automatically route to the VPC Service over Cloudflare’s network, regardless of where your Worker is executing:</p>
            <pre><code>export default {
  async fetch(request, env, ctx) {
    // Perform application logic in Workers here	

    // Call an external API running in a ECS in AWS when needed using the binding
    const response = await env.AWS_VPC_ECS_API.fetch("http://internal-host.com");

    // Additional application logic in Workers
    return new Response();
  },
};</code></pre>
            <p>Workers VPC is now available to everyone using Workers, at no additional cost during the beta, as is Cloudflare Tunnels. <a href="https://dash.cloudflare.com/?to=/:account/workers/vpc/services"><u>Try it out now.</u></a> And read on to learn more about how it works under the hood.</p>
    <div>
      <h2>Connecting the networks you trust, securely</h2>
      <a href="#connecting-the-networks-you-trust-securely">
        
      </a>
    </div>
    <p>Your applications span multiple networks, whether they are on-premise or in external clouds. But it’s been difficult to connect from Workers to your APIs and databases locked behind private networks. </p><p>We have <a href="https://blog.cloudflare.com/workers-virtual-private-cloud/"><u>previously described</u></a> how traditional virtual private clouds and networks entrench you into traditional clouds. While they provide you with workload isolation and security, traditional virtual private clouds make it difficult to build across clouds, access your own applications, and choose the right technology for your stack.</p><p>A significant part of the cloud lock-in is the inherent complexity of building secure, distributed workloads. VPC peering requires you to configure routing tables, security groups and network access-control lists, since it relies on networking across clouds to ensure connectivity. In many organizations, this means weeks of discussions and many teams involved to get approvals. This lock-in is also reflected in the solutions invented to wrangle this complexity: Each cloud provider has their own bespoke version of a “Private Link” to facilitate cross-network connectivity, further restricting you to that cloud and the vendors that have integrated with it.</p><p>With Workers VPC, we’re simplifying that dramatically. You set up your Cloudflare Tunnel once, with the necessary permissions to access your private network. Then, you can configure Workers VPC Services, with the tunnel and hostname (or IP address and port) of the service you want to expose to Workers. Any request made to that VPC Service will use this configuration to route to the given service within the network.</p>
            <pre><code>{
  "type": "http",
  "name": "vpc-service-name",
  "http_port": 80,
  "https_port": 443,
  "host": {
    "hostname": "internally-resolvable-hostname.com",
    "resolver_network": {
      "tunnel_id": "0191dce4-9ab4-7fce-b660-8e5dec5172da"
    }
  }
}</code></pre>
            <p>This ensures that, once represented as a Workers VPC Service, a service in your private network is secured in the same way other Cloudflare bindings are, using the Workers binding model. Let’s take a look at a simple VPC Service binding example:</p>
            <pre><code>{
  "name": "WORKER-NAME",
  "main": "./src/index.js",
  "vpc_services": [
    {
      "binding": "AWS_VPC2_ECS_API",
      "service_id": "5634563546"
    }
  ]
}</code></pre>
            <p>Like other Workers bindings, when you deploy a Worker project that tries to connect to a VPC Service, the access permissions are verified at deploy time to ensure that the Worker has access to the service in question. And once deployed, the Worker can use the VPC Service binding to make requests to that VPC Service — and only that service within the network. </p><p>That’s significant: Instead of exposing the entire network to the Worker, only the specific VPC Service can be accessed by the Worker. This access is verified at deploy time to provide a more explicit and transparent service access control than traditional networks and access-control lists do.</p><p>This is a key factor in the design of Workers bindings: de facto security with simpler management and making Workers immune to Server-Side Request Forgery (SSRF) attacks. <a href="https://blog.cloudflare.com/workers-environment-live-object-bindings/#security"><u>We’ve gone deep on the binding security model in the past</u></a>, and it becomes that much more critical when accessing your private networks. </p><p>Notably, the binding model is also important when considering what Workers are: scripts running on Cloudflare’s global network. They are not, in contrast to traditional clouds, individual machines with IP addresses, and do not exist within networks. Bindings provide secure access to other resources within your Cloudflare account – and the same applies to Workers VPC Services.</p>
    <div>
      <h2>A peek under the hood</h2>
      <a href="#a-peek-under-the-hood">
        
      </a>
    </div>
    <p>So how do VPC Services and their bindings route network requests from Workers anywhere on Cloudflare’s global network to regional networks using tunnels? Let’s look at the lifecycle of a sample HTTP Request made from a VPC Service’s dedicated <b>fetch()</b> request represented here:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4iUTiZjmbm2ujppLugfxJo/4db92fdf8549c239f52d8636e2589baf/image4.png" />
          </figure><p>It all starts in the Worker code, where the <b>.fetch() </b>function of the desired VPC Service is called with a standard JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/API/Request"><u>Request</u></a> (as represented with Step 1). The Workers runtime will use a <a href="https://capnproto.org/"><u>Cap’n Proto</u></a> remote-procedure-call to send the original HTTP request alongside additional context, as it does for many other Workers bindings. </p><p>The Binding Worker of the VPC Service System receives the HTTP request along with the binding context, in this case, the Service ID of the VPC Service being invoked. The Binding Worker will proxy this information to the Iris Service within an HTTP CONNECT connection, a standard pattern across Cloudflare’s bindings to place connection logic to Cloudflare’s edge services within Worker code rather than the Workers runtime itself (Step 2). </p><p>The Iris Service is the main service for Workers VPC. Its responsibility is to accept requests for a VPC Service and route them to the network in which your VPC Service is located. It does this by integrating with <a href="https://blog.cloudflare.com/extending-local-traffic-management-load-balancing-to-layer-4-with-spectrum/#how-we-enabled-spectrum-to-support-private-networks"><u>Apollo</u></a>, an internal service of <a href="https://developers.cloudflare.com/cloudflare-one/?cf_target_id=2026081E85C775AF31266A26CE7F3D4D"><u>Cloudflare One</u></a>. Apollo provides a unified interface that abstracts away the complexity of securely connecting to networks and tunnels, <a href="https://blog.cloudflare.com/from-ip-packets-to-http-the-many-faces-of-our-oxy-framework/"><u>across various layers of networking</u></a>. </p><p>To integrate with Apollo, Iris must complete two tasks. First, Iris will parse the VPC Service ID from the metadata and fetch the information of the tunnel associated with it from our configuration store. This includes the tunnel ID and type from the configuration store (Step 3), which is the information that Iris needs to send the original requests to the right tunnel.</p><p>Second, Iris will create the UDP datagrams containing DNS questions for the A and AAAA records of the VPC Service’s hostname. These datagrams will be sent first, via Apollo. Once DNS resolution is completed, the original request is sent along, with the resolved IP address and port (Step 4). That means that steps 4 through 7 happen in sequence twice for the first request: once for DNS resolution and a second time for the original HTTP Request. Subsequent requests benefit from Iris’ caching of DNS resolution information, minimizing request latency.</p><p>In Step 5, Apollo receives the metadata of the Cloudflare Tunnel that needs to be accessed, along with the DNS resolution UDP datagrams or the HTTP Request TCP packets. Using the tunnel ID, it determines which datacenter is connected to the Cloudflare Tunnel. This datacenter is in a region close to the Cloudflare Tunnel, and as such, Apollo will route the DNS resolution messages and the Original Request to the Tunnel Connector Service running in that datacenter (Step 5).</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6eXnv33qvTvGRRNGqS9ywj/99e57beeaa32de0724c6c9f396ab3b17/image3.png" />
          </figure><p>The Tunnel Connector Service is responsible for providing access to the Cloudflare Tunnel to the rest of Cloudflare’s network. It will relay the DNS resolution questions, and subsequently the original request to the tunnel over the QUIC protocol (Step 6).</p><p>Finally, the Cloudflare Tunnel will send the DNS resolution questions to the DNS resolver of the network it belongs to. It will then send the original HTTP Request from its own IP address to the destination IP and port (Step 7). The results of the request are then relayed all the way back to the original Worker, from the datacenter closest to the tunnel all the way to the original Cloudflare datacenter executing the Worker request.</p>
    <div>
      <h2>What VPC Service allows you to build</h2>
      <a href="#what-vpc-service-allows-you-to-build">
        
      </a>
    </div>
    <p>This unlocks a whole new tranche of applications you can build on Cloudflare. For years, Workers have excelled at the edge, but they've largely been kept "outside" your core infrastructure. They could only call public endpoints, limiting their ability to interact with the most critical parts of your stack—like a private accounts API or an internal inventory database. Now, with VPC Services, Workers can securely access those private APIs, databases, and services, fundamentally changing what's possible.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/DDDzgVtHtK92DZ4LwKhLI/904fc30fcab4797fd6ee263f09b85ab1/image2.png" />
          </figure><p>This immediately enables true cross-cloud applications that span Cloudflare Workers and any other cloud like AWS, GCP or Azure. We’ve seen many customers adopt this pattern over the course of our private beta, establishing private connectivity between their external clouds and Cloudflare Workers. We’ve even done so ourselves, connecting our Workers to Kubernetes services in our core datacenters to power the control plane APIs for many of our services. Now, you can build the same powerful, distributed architectures, using Workers for global scale while keeping stateful backends in the network you already trust.</p><p>It also means you can connect to your on-premise networks from Workers, allowing you to modernize legacy applications with the performance and infinite scale of Workers. More interesting still are some emerging use cases for developer workflows. We’ve seen developers run <a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/"><code><u>cloudflared</u></code></a> on their laptops to connect a deployed Worker back to their local machine for real-time debugging. The full flexibility of Cloudflare Tunnels is now a programmable primitive accessible directly from your Worker, opening up a world of possibilities.</p>
    <div>
      <h2>The path ahead of us</h2>
      <a href="#the-path-ahead-of-us">
        
      </a>
    </div>
    <p>VPC Services is the first milestone within the larger Workers VPC initiative, but we’re just getting started. Our goal is to make connecting to any service and any network, anywhere in the world, a seamless part of the Workers experience. Here’s what we’re working on next:</p><p><b>Deeper network integration</b>. Starting with Cloudflare Tunnels was a deliberate choice. It's a highly available, flexible, and familiar solution, making it the perfect foundation to build upon. To provide more options for enterprise networking, we're going to be adding support for standard IPsec tunnels, Cloudflare Network Interconnect (CNI), and AWS Transit Gateway, giving you and your teams more choices and potential optimizations. Crucially, these connections will also become truly bidirectional, allowing your private services to initiate connections back to Cloudflare resources such as pushing events to Queues or fetching from R2.</p><p><b>Expanded protocol and service support. </b>The next step beyond HTTP is enabling access to TCP services. This will first be achieved by integrating with Hyperdrive. We're evolving the previous Hyperdrive support for private databases to be simplified with VPC Services configuration, avoiding the need to add Cloudflare Access and manage security tokens. This creates a more native experience, complete with Hyperdrive's powerful connection pooling. Following this, we will add broader support for raw TCP connections, unlocking direct connectivity to services like Redis caches and message queues from <a href="https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/"><code><u>Workers ‘connect()’</u></code></a>.</p><p><b>Ecosystem compatibility. </b>We want to make connecting to a private service feel as natural as connecting to a public one. To do so, we will be providing a unique autogenerated hostname for each Workers VPC Service, similar to <a href="https://developers.cloudflare.com/hyperdrive/get-started/#write-a-worker"><u>Hyperdrive’s connection strings</u></a>. This will make it easier to use Workers VPC with existing libraries and object–relational mapping libraries that may require a hostname (e.g., in a global ‘<code>fetch()</code>’ call or a MongoDB connection string). Workers VPC Service hostname will automatically resolve and route to the correct VPC Service, just as the ‘<code>fetch()</code>’ command does.</p>
    <div>
      <h2>Get started with Workers VPC</h2>
      <a href="#get-started-with-workers-vpc">
        
      </a>
    </div>
    <p>We’re excited to release Workers VPC Services into open beta today. We’ve spent months building out and testing our first milestone for Workers to private network access. And we’ve refined it further based on feedback from both internal teams and customers during the closed beta. </p><p><b>Now, we’re looking forward to enabling everyone to build cross-cloud apps on Workers with Workers VPC, available for free during the open beta.</b> With Workers VPC, you can bring your apps on private networks to region Earth, closer to your users and available to Workers across the globe.</p><p><a href="https://dash.cloudflare.com/?to=/:account/workers/vpc/services"><b><u>Get started with Workers VPC Services for free now.</u></b></a></p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Workers VPC]]></category>
            <category><![CDATA[Cloudflare Tunnel]]></category>
            <category><![CDATA[Network]]></category>
            <category><![CDATA[Hybrid Cloud]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[VPC]]></category>
            <category><![CDATA[Private Network]]></category>
            <guid isPermaLink="false">3nRyPdIVogbDGSeUZgRY41</guid>
            <dc:creator>Thomas Gauvin</dc:creator>
            <dc:creator>Matt Alonso</dc:creator>
            <dc:creator>Eric Falcão</dc:creator>
        </item>
        <item>
            <title><![CDATA[Pools across the sea: how Hyperdrive speeds up access to databases and why we’re making it free]]></title>
            <link>https://blog.cloudflare.com/how-hyperdrive-speeds-up-database-access/</link>
            <pubDate>Tue, 08 Apr 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Hyperdrive, Cloudflare's global connection pooler, relies on some key innovations to make your database connections work. Let's dive deeper, in celebration of its availability for Free Plan customers. ]]></description>
            <content:encoded><![CDATA[ <p></p><p></p>
    <div>
      <h2>Free as in beer</h2>
      <a href="#free-as-in-beer">
        
      </a>
    </div>
    <p>In acknowledgement of its pivotal role in building distributed applications that rely on regional databases, we’re making Hyperdrive available on the free plan of Cloudflare Workers!</p><p><a href="https://developers.cloudflare.com/hyperdrive/"><u>Hyperdrive</u></a> enables you to build performant, global apps on Workers with <a href="https://developers.cloudflare.com/hyperdrive/examples/"><u>your existing SQL databases</u></a>. Tell it your database connection string, bring your existing drivers, and Hyperdrive will make connecting to your database faster. No major <a href="https://www.cloudflare.com/learning/cloud/how-to-refactor-applications/">refactors</a> or convoluted configuration required.</p><p>Over the past year, Hyperdrive has become a key service for teams that want to build their applications on Workers and connect to SQL databases. This includes our own engineering teams, with Hyperdrive serving as the tool of choice to connect from Workers to our own Postgres clusters for many of the control-plane actions of our billing, <a href="https://www.cloudflare.com/developer-platform/products/d1/"><u>D1</u></a>, <a href="https://www.cloudflare.com/developer-platform/products/r2/"><u>R2</u></a>, and <a href="https://www.cloudflare.com/developer-platform/products/workers-kv/"><u>Workers KV</u></a> teams (just to name a few). </p><p>This has highlighted for us that Hyperdrive is a fundamental building block, and it solves a common class of problems for which there isn’t a great alternative. We want to make it possible for everyone building on Workers to connect to their database of choice with the best performance possible, using the drivers and frameworks they already know and love.</p>
    <div>
      <h3>Performance is a feature</h3>
      <a href="#performance-is-a-feature">
        
      </a>
    </div>
    <p>To illustrate how much Hyperdrive can improve your application’s performance, let’s write the world’s simplest benchmark. This is obviously not production code, but is meant to be reflective of a common application you’d bring to the Workers platform. We’re going to use a simple table, a very popular OSS driver (<a href="https://github.com/porsager/postgres"><u>postgres.js</u></a>), and run a standard OLTP workload from a Worker. We’re going to keep our origin database in London, and query it from Chicago (those locations will come back up later, so keep them in mind).</p>
            <pre><code>// This is the test table we're using
// CREATE TABLE IF NOT EXISTS test_data(userId bigint, userText text, isActive bool);

import postgres from 'postgres';

let direct_conn = '&lt;direct connection string here!&gt;';
let hyperdrive_conn = env.HYPERDRIVE.connectionString;

async function measureLatency(connString: string) {
	let beginTime = Date.now();
	let sql = postgres(connString);

	await sql`INSERT INTO test_data VALUES (${999}, 'lorem_ipsum', ${true})`;
	await sql`SELECT userId, userText, isActive FROM test_data WHERE userId = ${999}`;

	let latency = Date.now() - beginTime;
	ctx.waitUntil(sql.end());
	return latency;
}

let directLatency = await measureLatency(direct_conn);
let hyperdriveLatency = await measureLatency(hyperdrive_conn);</code></pre>
            <p>The code above</p><ol><li><p>Takes a standard database connection string, and uses it to create a database connection.</p></li><li><p>Loads a user record into the database.</p></li><li><p>Queries all records for that user.</p></li><li><p>Measures how long this takes to do with a direct connection, and with Hyperdrive.</p></li></ol><p>When connecting directly to the origin database, this set of queries takes an average of 1200 ms. With absolutely no other changes, just swapping out the connection string for <code>env.HYPERDRIVE.connectionString</code>, this number is cut down to 500 ms (an almost 60% reduction). If you enable Hyperdrive’s caching, so that the SELECT query is served from cache, this takes only 320 ms. With this one-line change, Hyperdrive will reduce the latency of this Worker by almost 75%! In addition to this speedup, you also get secure auth and transport, as well as a connection pool to help protect your database from being overwhelmed when your usage scales up. See it for yourself using our <a href="https://hyperdrive-demo.pages.dev/"><u>demo application</u></a>.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6TTbEV9d7NClGk0iRmkEG3/4d5e4fdeb195337a92942bc7e13dbb6f/image7.png" />
          </figure><p><sup><i>A demo application comparing latencies between Hyperdrive and direct-to-database connections.</i></sup></p><p>Traditional SQL databases are familiar and powerful, but they are designed to be colocated with long-running compute. They were not conceived in the era of modern serverless applications, and have connection models that don't take the constraints of such an environment into account. Instead, they require highly stateful connections that do not play well with Workers’ global and stateless model. Hyperdrive solves this problem by maintaining database connections across Cloudflare’s network ready to be used at a moment’s notice, caching your queries for fast access, and eliminating round trips to minimize network latency.</p><p>With this announcement, many developers are going to be taking a look at Hyperdrive for the first time over the coming weeks and months. To help people dive in and try it out, we think it’s time to talk about how Hyperdrive actually works.</p>
    <div>
      <h2>Staying warm in the pool</h2>
      <a href="#staying-warm-in-the-pool">
        
      </a>
    </div>
    <p>Let’s talk a bit about database connection poolers, how they work, and what problems they already solve. They are <a href="https://github.com/pgbouncer/pgbouncer/commit/a0d2b294e0270f8a246e5b98f0700716c0672b0d"><u>hardly a new technology</u></a>, after all. </p><p>The point of any connection pooler, Hyperdrive or others, is to minimize the overhead of establishing and coordinating database connections. Every new database connection requires additional <a href="https://blog.anarazel.de/2020/10/07/measuring-the-memory-overhead-of-a-postgres-connection/"><u>memory</u></a> and CPU time from the database server, and this can only scale just so well as the number of concurrent connections climbs. So the question becomes, how should database connections be shared across clients? </p><p>There are three <a href="https://www.pgbouncer.org/features.html"><u>commonly-used approaches</u></a> for doing so. These are:</p><ul><li><p><b>Session mode:</b> whenever a client connects, it is assigned a connection of its own until it disconnects. This dramatically reduces the available concurrency, in exchange for much simpler implementation and a broader selection of supported features</p></li><li><p><b>Transaction mode:</b> when a client is ready to send a query or open a transaction, it is assigned a connection on which to do so. This connection will be returned to the pool when the query or transaction concludes. Subsequent queries during the same client session may (or may not) be assigned a different connection.</p></li><li><p><b>Statement mode:</b> Like transaction mode, but a connection is given out and returned for each statement. Multi-statement transactions are disallowed.</p></li></ul><p>When building Hyperdrive, we had to decide which of these modes we wanted to use. Each of the approaches implies some <a href="https://jpcamara.com/2023/04/12/pgbouncer-is-useful.html"><u>fairly serious tradeoffs</u></a>, so what’s the right choice? For a service intended to make using a database from Workers as pleasant as possible we went with the choice that balances features and performance, and designed Hyperdrive as a transaction-mode pooler. This best serves the goals of supporting a large number of short-lived clients (and therefore very high concurrency), while still supporting the transactional semantics that cause so many people to reach for an RDBMS in the first place.</p><p>In terms of this part of its design, Hyperdrive takes its cues from many pre-existing popular connection poolers, and manages operations to allow our users to focus on designing their full-stack applications. There is a configured limit to the number of connections the pool will give out, limits to how long a connection will be held idle until it is allowed to drop and return resources to the database, bookkeeping around <a href="https://blog.cloudflare.com/elephants-in-tunnels-how-hyperdrive-connects-to-databases-inside-your-vpc-networks/"><u>prepared statements</u></a> being shared across pooled connections, and other traditional concerns of the management of these resources to help ensure the origin database is able to run smoothly. These are all described in <a href="https://developers.cloudflare.com/hyperdrive/platform/limits/"><u>our documentation</u></a>.</p>
    <div>
      <h2>Round and round we go</h2>
      <a href="#round-and-round-we-go">
        
      </a>
    </div>
    <p>Ok, so why build Hyperdrive then? Other poolers that solve these problems already exist — couldn’t developers using Workers just run one of those and call it a day? It turns out that connecting to regional poolers from Workers has the same major downside as connecting to regional databases: network latency and round trips.</p><p>Establishing a connection, whether to a database or a pool, requires many exchanges between the client and server. While this is true for all fully-fledged client-server databases (e.g. <a href="https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase.html"><u>MySQL</u></a>, <a href="https://github.com/mongodb/specifications/blob/master/source/auth/auth.md"><u>MongoDB</u></a>), we are going to focus on the <a href="https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-START-UP"><u>PostgreSQL</u></a> connection protocol flow in this post. As we work through all of the steps involved, what we most want to keep track of is how many round trips it takes to accomplish. Note that we’re mostly concerned about having to wait around while these happen, so “half” round trips such as in the first diagram are not counted. This is because we can send off the message and then proceed without waiting.</p><p>The first step to establishing a connection between Postgres client and server is very familiar ground to anyone who’s worked much with networks: <a href="https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/"><u>a TCP startup handshake</u></a>. Postgres uses TCP for its underlying transport, and so we must have that connection before anything else can happen on top of it.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/58qrxBsbOXbFCFBzkZFIff/19caf62d24cdbf9c4ad69bfd8286e022/image5.png" />
          </figure><p>With our transport layer in place, the next step is to <a href="https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-SSL"><u>encrypt</u></a> the connection. The <a href="https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/"><u>TLS Handshake</u></a> involves some back-and-forth in its own right, though this has been reduced to just one round trip for TLS 1.3. Below is the simplest and fastest version of this exchange, but there are certainly scenarios where it can be much more complex.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5q7fVVQkB9Q43X3eaE76GP/b69c0ce964df370bd0609242f8e3de0c/image4.png" />
          </figure><p>After the underlying transport is established and secured, the application-level traffic can actually start! However, we’re not quite ready for queries, the client still needs to authenticate to a specific user and database. Again, there are multiple supported approaches that offer varying levels of speed and security. To make this comparison as fair as possible, we’re again going to consider the version that offers the fastest startup (password-based authentication).</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7KU6NHgZAW95nQyobo9Zwn/5f61d6e9ab6233186c865a9093a7f352/image8.png" />
          </figure><p>So, for those keeping score, establishing a new connection to your database takes a bare minimum of 5 round trips, and can very quickly climb from there. </p><p>While the latency of any given network round trip is going to vary based on so many factors that “it depends” is the only meaningful measurement available, some quick benchmarking during the writing of this post shows ~125 ms from Chicago to London. Now multiply that number by 5 round trips and the problem becomes evident: 625 ms to start up a connection is not viable in a distributed serverless environment. So how does Hyperdrive solve it? What if I told you the trick is that we do it all twice? To understand Hyperdrive’s secret sauce, we need to dive into Hyperdrive’s architecture.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/291ua8XgVnowWDOfEm05eR/a2674a9a393fcaaef8e2cfe64dd57402/image1.png" />
          </figure>
    <div>
      <h2>Impersonating a database server</h2>
      <a href="#impersonating-a-database-server">
        
      </a>
    </div>
    <p>The rest of this post is a deep dive into answering the question of how Hyperdrive does what it does. To give the clearest picture, we’re going to talk about some internal subsystems by name. To help keep everything straight, let’s start with a short glossary that you can refer back to if needed. These descriptions may not make sense yet, but they will by the end of the article.
</p><table><tr><td><p><b>Hyperdrive subsystem name</b></p></td><td><p><b>Brief description</b></p></td></tr><tr><td><p>Client</p></td><td><p>Lives on the same server as your Worker, talks directly to your database driver. This caches query results and sends queries to Endpoint if needed.</p></td></tr><tr><td><p>Endpoint</p></td><td><p>Lives in the data center nearest to your origin database, talks to your origin database. This caches query results and houses a pool of connections to your origin database.</p></td></tr><tr><td><p>Edge Validator</p></td><td><p>Sends a request to a Cloudflare data center to validate that Hyperdrive can connect to your origin database at time of creation.</p></td></tr><tr><td><p>Placement</p></td><td><p>Builds on top of Edge Validator to connect to your origin database from all eligible data centers, to identify which have the fastest connections.</p></td></tr></table><p>The first subsystem we want to dig into is named <code>Client. Client</code>’s first job is to pretend to be a database server. When a user’s Worker wants to connect to their database via Hyperdrive, they use a special connection string that the Worker runtime generates on the fly. This tells the Worker to reach out to a Hyperdrive process running on the same Cloudflare server, and direct all traffic to and from the database client to it.</p>
            <pre><code>import postgres from "postgres";

// Connect to Hyperdrive
const sql = postgres(env.HYPERDRIVE.connectionString);

// sql will now talk over an RPC channel to Hyperdrive, instead of via TCP to Postgres</code></pre>
            <p>Once this connection is established, the database driver will perform the usual handshake expected of it, with our <code>Client</code> playing the role of a database server and sending the appropriate responses. All of this happens on the same Cloudflare server running the Worker, and we observe that the p90 for all this is 4 ms (p50 is 2 ms). Quite a bit better than 625 ms, but how does that help? The query still needs to get to the database, right?</p><p><code>Client</code>’s second main job is to inspect the queries sent from a Worker, and decide whether they can be served from Cloudflare’s cache. We’ll talk more about that later on. Assuming that there are no cached query results available, <code>Client</code> will need to reach out to our second important subsystem, which we call <code>Endpoint</code>.</p>
    <div>
      <h2>In for the long haul</h2>
      <a href="#in-for-the-long-haul">
        
      </a>
    </div>
    <p>Before we dig into the role <code>Endpoint</code> plays, it’s worth talking more about how the <code>Client→Endpoint</code> connection works, because it’s a key piece of our solution. We have already talked a lot about the price of network round trips, and how a Worker might be quite far away from the origin database, so how does Hyperdrive handle the long trip from the <code>Client</code> running alongside their Worker to the <code>Endpoint</code> running near their database without expensive round trips?</p><p>This is accomplished with a very handy bit of Cloudflare’s networking infrastructure. When <code>Client</code> gets a cache miss, it will submit a request to our networking platform for a connection to whichever data center <code>Endpoint</code> is running on. This platform keeps a pool of ready TCP connections between all of Cloudflare’s data centers, such that we don’t need to do any preliminary handshakes to begin sending application-level traffic. You might say we put a connection pooler in our connection pooler.</p><p>Over this TCP connection, we send an initialization message that includes all of the buffered query messages the Worker has sent to <code>Client</code> (the mental model would be something like a <code>SYN</code> and a payload all bundled together). <code>Endpoint</code> will do its job processing this query, and respond by streaming the response back to <code>Client</code>, leaving the streaming channel open for any followup queries until <code>Client</code> disconnects. This approach allows us to send queries around the world with zero wasted round trips.</p>
    <div>
      <h2>Impersonating a database client</h2>
      <a href="#impersonating-a-database-client">
        
      </a>
    </div>
    <p><code>Endpoint</code> has a couple different jobs it has to do. Its first job is to pretend to be a database client, and to do the client half of the handshake shown above. Second, it must also do the same query processing that <code>Client</code> does with query messages. Finally, <code>Endpoint</code> will make the same determination on when it needs to reach out to the origin database to get uncached query results.</p><p>When <code>Endpoint</code> needs to query the origin database, it will attempt to take a connection out of a limited-size pool of database connections that it keeps. If there is an unused connection available, it is handed out from the pool and used to ferry the query to the origin database, and the results back to <code>Endpoint</code>. Once <code>Endpoint</code> has these results, the connection is immediately returned to the pool so that another <code>Client</code> can use it. These warm connections are usable in a matter of microseconds, which is obviously a dramatic improvement over the round trips from one region to another that a cold startup handshake would require.</p><p>If there are no currently unused connections sitting in the pool, it may start up a new one (assuming the pool has not already given out as many connections as it is allowed to). This set of handshakes looks exactly the same as the one <code>Client</code> does, but it happens across the network between a Cloudflare data center and wherever the origin database happens to be. These are the same 5 round trips as our original example, but instead of a full Chicago→London path on every single trip, perhaps it’s Virginia→London, or even London→London. Latency here will depend on which data center <code>Endpoint</code> is being housed in.</p>
    <div>
      <h2>Distributed choreography</h2>
      <a href="#distributed-choreography">
        
      </a>
    </div>
    <p>Earlier, we mentioned that Hyperdrive is a transaction-mode pooler. This means that when a driver is ready to send a query or open a transaction it must get a connection from the pool to use. The core challenge for a transaction-mode pooler is in aligning the state of the driver with the state of the connection checked out from the pool. For example, if the driver thinks it’s in a transaction, but the database doesn’t, then you might get errors or even corrupted results.</p><p>Hyperdrive achieves this by ensuring all connections are in the same state when they’re checked out of the pool: idle and ready for a query. Where Hyperdrive differs from other transaction-mode poolers is that it does this dance of matching up the states of two different connections across machines, such that there’s no need to share state between <code>Client</code> and <code>Endpoint</code>! Hyperdrive can terminate the incoming connection in <code>Client</code> on the same machine running the Worker, and pool the connections to the origin database wherever makes the most sense.</p><p>The job of a transaction-mode pooler is a hard one. Database connections are fundamentally stateful and keeping track of that state is important to maintain our guise when impersonating either a database client or a server. As an example, one of the trickier pieces of state to manage are <a href="https://www.postgresql.org/docs/current/protocol-overview.html#PROTOCOL-QUERY-CONCEPTS"><u>prepared statements</u></a>. When a user creates a new prepared statement, the prepared statement is only created on whichever database connection happened to be checked out at that time. Once the user finishes the transaction or query they are processing, the connection holding that statement is returned to the pool. From the user’s perspective they’re still connected using the same database connection, so a new query or transaction can reasonably expect to use that previously prepared statement. If a different connection is handed out for the next query and the query wants to make use of this resource, the pooler has to do something about it. We went into some depth on this topic in a <a href="https://blog.cloudflare.com/postgres-named-prepared-statements-supported-hyperdrive/"><u>previous blog post</u></a> when we released this feature, but in sum, the process looks like this:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ibtnO4URpLJ6m3Nyd2kpW/331059a6fd18c7d70b95a15af8f57cd6/image2.png" />
          </figure><p>Hyperdrive implements this by keeping track of what statements have been prepared by a given client, as well as what statements have been prepared on each origin connection in the pool. When a query comes in expecting to re-use a particular prepared statement (#8 above), Hyperdrive checks if it’s been prepared on the checked-out origin connection. If it hasn’t, Hyperdrive will replay the wire-protocol message sequence to prepare it on the newly-checked-out origin connection (#10 above) before sending the query over it. Many little corrections like this are necessary to keep the client’s connection to Hyperdrive and Hyperdrive’s connection to the origin database lined up so that both sides see what they expect.</p>
    <div>
      <h2>Better, faster, smarter, closer</h2>
      <a href="#better-faster-smarter-closer">
        
      </a>
    </div>
    <p>This “split connection” approach is the founding innovation of Hyperdrive, and one of the most vital aspects of it is how it affects starting up new connections. While the same 5+ round trips must always happen on startup, the actual time spent on the round trips can be dramatically reduced by conducting them over the smallest possible distances. This impact of distance can be so big that there is still a huge latency reduction even though the startup round trips must now happen <i>twice</i> (once each between the Worker and <code>Client</code>, and <code>Endpoint</code> and your origin database). So how do we decide where to run everything, to lean into that advantage as much as possible?</p><p>The placement of <code>Client</code> has not really changed since the original design of Hyperdrive. Sharing a server with the Worker sending the queries means that the Worker runtime can connect directly to Hyperdrive with no network hop needed. While there is always room for microoptimizations, it’s hard to do much better than that from an architecture perspective.  By far the bigger piece of the latency puzzle is where to run <code>Endpoint</code>.</p><p>Hyperdrive keeps a list of data centers that are eligible to house <code>Endpoint</code>s, requiring that they have sufficient capacity and the best routes available for pooled connections to use. The key challenge to overcome here is that a <a href="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS"><u>database connection string</u></a> does not tell you where in the world a database actually is. The reality is that reliably going from a hostname to a precise (enough) geographic location is a hard problem, even leaving aside the additional complexity of doing so <a href="https://blog.cloudflare.com/elephants-in-tunnels-how-hyperdrive-connects-to-databases-inside-your-vpc-networks/"><u>within a private network</u></a>. So how do we pick from that list of eligible data centers?</p><p>For much of the time since its launch, Hyperdrive solved this with a regional pool approach. When a Worker connected to Hyperdrive, the location of the Worker was used to infer what region the end user was connecting from (e.g. ENAM, WEUR, APAC, etc. — see a rough breakdown <a href="https://www.cloudflare.com/network/"><u>here</u></a>). Data centers to house <code>Endpoint</code>s for any given Hyperdrive were deterministically selected from that region’s list of eligible options using <a href="https://en.wikipedia.org/wiki/Rendezvous_hashing"><u>rendezvous hashing</u></a>, resulting in one pool of connections <i>per region</i>.</p><p>This approach worked well enough, but it had some severe shortcomings. The first and most obvious is that there’s no guarantee that the data center selected for a given region is actually closer to the origin database than the user making the request. This means that, while you’re getting the benefit of the excellent routing available on <a href="https://www.cloudflare.com/network/"><u>Cloudflare's network</u></a>, you may be going significantly out of your way to do so. The second downside is that, in the scenario where a new connection must be created, the round trips to do so may be happening over a significantly larger distance than is necessary if the origin database is in a different region than the <code>Endpoint</code> housing the regional connection pool. This increases latency and reduces throughput for the query that needs to instantiate the connection.</p><p>The final key downside here is an unfortunate interaction with <a href="https://developers.cloudflare.com/workers/configuration/smart-placement/"><u>Smart Placement</u></a>, a feature of Cloudflare Workers that analyzes the duration of your Worker requests to identify the data center to run your Worker in. With regional <code>Endpoint</code>s, the best Smart Placement can possibly do is to put your requests close to the <code>Endpoint</code> for whichever region the origin database is in. Again, there may be other data centers that are closer, but Smart Placement has no way to do better than where the <code>Endpoint</code> is because all Hyperdrive queries must route through it.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3y9r3Dwn6APp5Pw6kqkg0Z/3a9e202670b6c65a22294fe777064add/image6.png" />
          </figure><p>We recently <a href="https://developers.cloudflare.com/changelog/2025-03-04-hyperdrive-pooling-near-database-and-ip-range-egress/"><u>shipped some improvements</u></a> to this system that significantly enhanced performance. The new system discards the concept of regional pools entirely, in favor of a single global <code>Endpoint</code> for each Hyperdrive that is in the eligible data center as close as possible to the origin database.</p><p>The way we solved locating the origin database such that we can accomplish this was ultimately very straightforward. We already had a subsystem to confirm, at the time of creation, that Hyperdrive could connect to an origin database using the provided information. We call this subsystem our <code>Edge Validator</code>.</p><p>It’s bad user experience to allow someone to create a Hyperdrive, and then find out when they go to use it that they mistyped their password or something. Now they’re stuck trying to debug with extra layers in the way, with a Hyperdrive that can’t possibly work. Instead, whenever a Hyperdrive is created, the <code>Edge Validator</code> will send a request to an arbitrary data center to use its instance of Hyperdrive to connect to the origin database. If this connection fails, the creation of the Hyperdrive will also fail, giving immediate feedback to the user at the time it is most helpful.</p><p>With our new subsystem, affectionately called <code>Placement</code>, we now have a solution to the geolocation problem. After <code>Edge Validator</code> has confirmed that the provided information works and the Hyperdrive is created, an extra step is run in the background. <code>Placement</code> will perform the exact same connection routine, except instead of being done once from an arbitrary data center, it is run a handful of times from every single data center that is eligible to house <code>Endpoints</code>. The latency of establishing these connections is collected, and the average is sent back to a central instance of <code>Placement</code>. The data centers that can connect to the origin database the fastest are, by definition, where we want to run <code>Endpoint</code> for this Hyperdrive. The list of these is saved, and at runtime is used to select the <code>Endpoint</code> best suited to housing the pool of connections to the origin database.</p><p>Given that the secret sauce of Hyperdrive is in managing and minimizing the latency of establishing these connections, moving <code>Endpoint</code>s right next to their origin databases proved to be pretty impactful.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MZpaxXjj4tlOAinZkDqOF/e1a555a47141ac11aa391d27806cbfbc/image9.png" />
          </figure><p><sup><i>Pictured: query latency as measured from Endpoint to origin databases. The backfill of Placement to existing customers was done in stages on 02/22 and 02/25.</i></sup></p>
    <div>
      <h2>Serverless drivers exist, though?</h2>
      <a href="#serverless-drivers-exist-though">
        
      </a>
    </div>
    <p>While we went in a different direction, it’s worth acknowledging that other teams have <a href="https://neon.tech/blog/quicker-serverless-postgres"><u>solved this same problem</u></a> with a very different approach. Custom database drivers, usually called “serverless drivers”, have made several optimization efforts to reduce both the number of round trips and how quickly they can be conducted, while still connecting directly from your client to your database in the traditional way. While these drivers are impressive, we chose not to go this route for a couple of reasons.</p><p>First off, a big part of the appeal of using Postgres is its <a href="https://www.lastweekinaws.com/podcast/screaming-in-the-cloud/the-ever-growing-ecosystem-of-postgres-with-alvaro-hernandez/"><u>vibrant ecosystem</u></a>. Odds are good you’ve used Postgres before, and it can probably help solve whichever problem you’re tackling with your newest project. This familiarity and shared knowledge across projects is an absolute superpower. We wanted to lean into this advantage by supporting the most popular drivers already in this ecosystem, instead of fragmenting it by adding a competing one.</p><p>Second, Hyperdrive also functions as a cache for individual queries (a bit of trivia: its name while still in Alpha was actually <code>sql-query-cache</code>). Doing this as effectively as possible for distributed users requires some clever positioning of where exactly the query results should be cached. One of the unique advantages of running a distributed service on Cloudflare’s network is that we have a lot of flexibility on where to run things, and can confidently surmount challenges like those. If we’re going to be playing three-card monte with where things are happening anyway, it makes the most sense to favor that route for solving the other problems we’re trying to tackle too.</p>
    <div>
      <h2>Pick your favorite cache pun</h2>
      <a href="#pick-your-favorite-cache-pun">
        
      </a>
    </div>
    <p>As we’ve <a href="https://blog.cloudflare.com/postgres-named-prepared-statements-supported-hyperdrive/"><u>talked about</u></a> in the past, Hyperdrive buffers protocol messages until it has enough information to know whether a query can be served from cache. In a post about how Hyperdrive works it would be a shame to skip talking about how exactly we cache query results, so let’s close by diving into that.</p><p>First and foremost, Hyperdrive uses <a href="https://developers.cloudflare.com/cache/"><u>Cloudflare's cache</u></a>, because when you have technology like that already available to you, it’d be silly not to use it. This has some implications for our architecture that are worth exploring.</p><p>The cache exists in each of Cloudflare’s data centers, and by default these are separate instances. That means that a <code>Client</code> operating close to the user has one, and an <code>Endpoint</code> operating close to the origin database has one. However, historically we weren’t able to take full advantage of that, because the logic for interacting with cache was tightly bound to the logic for managing the pool of connections.</p><p>Part of our recent architecture refactoring effort, where we switched to global <code>Endpoint</code>s, was to split up this logic such that we can take advantage of <code>Client</code>’s cache too. This was necessary because, with <code>Endpoint</code> moving to a single location for each Hyperdrive, users from other regions would otherwise have gotten cache hits served from almost as far away as the origin.</p><p>With the new architecture, the role of <code>Client</code> during active query handling transitioned from that of a “dumb pipe” to more like what <code>Endpoint</code> had always been doing. It now buffers protocol messages, and serves results from cache if possible. In those scenarios, Hyperdrive’s traffic never leaves the data center that the Worker is running in, reducing query latencies from 20-70 ms to an average of around 4 ms. As a side benefit, it also substantially reduces the network bandwidth Hyperdrive uses to serve these queries. A win-win!</p><p>In the scenarios where query results can’t be served from the cache in <code>Client</code>’s data center, all is still not lost. <code>Endpoint</code> may also have cached results for this query, because it can field traffic from many different <code>Client</code>s around the world. If so, it will provide these results back to <code>Client</code>, along with how much time is remaining before they expire, such that <code>Client</code> can both return them and store them correctly into its own cache. Likewise, if <code>Endpoint</code> does need to go to the origin database for results, they will be stored into both <code>Client</code> and <code>Endpoint</code> caches. This ensures that followup queries from that same <code>Client</code> data center will get the happy path with single-digit ms response times, and also reduce load on the origin database from any other <code>Client</code>’s queries. This functions similarly to how <a href="https://developers.cloudflare.com/cache/how-to/tiered-cache/"><u>Cloudflare's Tiered Cache</u></a> works, with <code>Endpoint</code>’s cache functioning as a final layer of shielding for the origin database.</p>
    <div>
      <h2>Come on in, the water’s fine!</h2>
      <a href="#come-on-in-the-waters-fine">
        
      </a>
    </div>
    <p>With this announcement of a Free Plan for Hyperdrive, and newly armed with the knowledge of how it works under the hood, we hope you’ll enjoy building your next project with it! You can get started with a single Wrangler command (or using the dashboard):</p>
            <pre><code>wrangler hyperdrive create postgres-hyperdrive 
--connection-string="postgres://user:password@db-host.example.com:5432/defaultdb"</code></pre>
            <p>We’ve also included a Deploy to Cloudflare button below to let you get started with a sample Worker app using Hyperdrive, just bring your existing Postgres database! If you have any questions or ideas for future improvements, please feel free to visit our <a href="https://discord.com/channels/595317990191398933/1150557986239021106"><u>Discord channel!</u></a></p><a href="https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/main/postgres-hyperdrive-template"><img src="https://deploy.workers.cloudflare.com/button" /></a>
<p></p><p></p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Hyperdrive]]></category>
            <category><![CDATA[Smart Placement]]></category>
            <category><![CDATA[SQL]]></category>
            <guid isPermaLink="false">3YedZXQKWaCm2jUQPvAeQv</guid>
            <dc:creator>Andrew Repp</dc:creator>
            <dc:creator>Matt Alonso</dc:creator>
        </item>
        <item>
            <title><![CDATA[Durable Objects Alarms — a wake-up call for your applications]]></title>
            <link>https://blog.cloudflare.com/durable-objects-alarms/</link>
            <pubDate>Wed, 11 May 2022 12:59:17 GMT</pubDate>
            <description><![CDATA[ Durable Object alarms let you call a function at a defined point in the future, unlocking deeper use-cases for Durable Objects like reliable queuing ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Since we launched Durable Objects, developers have leveraged them as a novel building block for distributed applications.</p><p>Durable Objects provide globally unique instances of a JavaScript class a developer writes, accessed via a unique ID. The Durable Object associated with each ID implements some fundamental component of an application — a banking application might have a Durable Object representing each bank account, for example. The bank account object would then expose methods for incrementing a balance, transferring money or any other actions that the application needs to do on the bank account.</p><p>Durable Objects work well as a stateful backend for applications — while Workers can instantiate a new instance of your code in any of Cloudflare’s data centers in response to a request, Durable Objects guarantee that all requests for a given Durable Object will reach the same instance on Cloudflare’s network.</p><p>Each Durable Object is single-threaded and has access to a stateful storage API, making it easy to build consistent and highly-available distributed applications on top of them.</p><p>This system makes distributed systems’ development easier — we’ve seen some impressive applications launched atop Durable Objects, from collaborative whiteboarding tools to conflict-free replicated data type (CRDT) systems for coordinating distributed state launch.</p><p>However, up until now, there’s been a piece missing — how do you invoke a Durable Object when a client Worker is not making requests to it?</p><p>As with any distributed system, Durable Objects can become unavailable and stop running. Perhaps the machine you were running on was unplugged, or the datacenter burned down and is never coming back, or an individual object exceeded its memory limit and was reset. Before today, a subsequent request would reinitialize the Durable Object on another machine, but there was no way to programmatically wake up an Object.</p><p>Durable Objects Alarms are here to change that, unlocking new use cases for Durable Objects like queues and deferred processing.</p>
    <div>
      <h3>What is a Durable Object Alarm?</h3>
      <a href="#what-is-a-durable-object-alarm">
        
      </a>
    </div>
    <p>Durable Object Alarms allow you, from within your Durable Object, to schedule the object to be woken up at a time in the future. When the alarm’s scheduled time comes, the Durable Object’s <code>alarm()</code> handler will be called. If this handler throws an exception, the alarm will be automatically retried using exponential backoff until it succeeds — alarms have guaranteed at-least-once execution.</p>
    <div>
      <h3>How are Alarms different from Workers Cron Triggers?</h3>
      <a href="#how-are-alarms-different-from-workers-cron-triggers">
        
      </a>
    </div>
    <p>Alarms are more fine-grained than Cron Triggers. While a Workers service can have up to three Cron Triggers configured at once, it can have an unlimited amount of Durable Objects, each of which can have a single alarm active at a time.</p><p>Alarms are directly scheduled from and invoke a function within your Durable Object. Cron Triggers, on the other hand, are not programmatic — they execute based on their schedules, which have to be configured via the Cloudflare Dashboard or centralized configuration APIs.</p>
    <div>
      <h3>How do I use Alarms?</h3>
      <a href="#how-do-i-use-alarms">
        
      </a>
    </div>
    <p>First, you’ll need to add the <code>durable_object_alarms</code> compatibility flag to your <code>wrangler.toml</code>.</p>
            <pre><code>compatibility_flags = ["durable_object_alarms"]</code></pre>
            <p>Next, implement an <code>alarm()</code> handler in your Durable Object that will be called when the alarm executes. From anywhere else in your Durable Object, call <code>state.storage.setAlarm()</code> and pass in a time for the alarm to run at. You can use <code>state.storage.getAlarm()</code> to retrieve the currently set alarm time.</p><p>In this example, we implemented an alarm handler that wakes the Durable Object up once every 10 seconds to batch requests to a single Durable Object, deferring processing until there is enough work in the queue for it to be worthwhile to process them.</p>
            <pre><code>export default {
  async fetch(request, env) {
    let id = env.BATCHER.idFromName("foo");
    return await env.BATCHER.get(id).fetch(request);
  },
};

const SECONDS = 1000;

export class Batcher {
  constructor(state, env) {
    this.state = state;
    this.storage = state.storage;
    this.state.blockConcurrencyWhile(async () =&gt; {
      let vals = await this.storage.list({ reverse: true, limit: 1 });
      this.count = vals.size == 0 ? 0 : parseInt(vals.keys().next().value);
    });
  }
  async fetch(request) {
    this.count++;

    // If there is no alarm currently set, set one for 10 seconds from now
    // Any further POSTs in the next 10 seconds will be part of this kh.
    let currentAlarm = await this.storage.getAlarm();
    if (currentAlarm == null) {
      this.storage.setAlarm(Date.now() + 10 * SECONDS);
    }

    // Add the request to the batch.
    await this.storage.put(this.count, await request.text());
    return new Response(JSON.stringify({ queued: this.count }), {
      headers: {
        "content-type": "application/json;charset=UTF-8",
      },
    });
  }
  async alarm() {
    let vals = await this.storage.list();
    await fetch("http://example.com/some-upstream-service", {
      method: "POST",
      body: Array.from(vals.values()),
    });
    await this.storage.deleteAll();
    this.count = 0;
  }
}</code></pre>
            <p>Once every 10 seconds, the <code>alarm()</code> handler will be called. In the event an unexpected error terminates the Durable Object, it will be re-instantiated on another machine, following a short delay, after which it can continue processing.</p><p>Under the hood, Alarms are implemented by making reads and writes to the storage layer. This means Alarm <code>get</code> and <code>set</code> operations follow the same rules as any other storage operation – writes are coalesced with other writes, and reads have a defined ordering. See <a href="/durable-objects-easy-fast-correct-choose-three/">our blog post</a> on the caching layer we implemented for Durable Objects for more information.</p>
    <div>
      <h3>Durable Objects Alarms guarantee fault-tolerance</h3>
      <a href="#durable-objects-alarms-guarantee-fault-tolerance">
        
      </a>
    </div>
    <p>Alarms are designed to have no single point of failure and to run entirely on our edge – every Cloudflare data center running Durable Objects is capable of running alarms, including migrating Durable Objects from unhealthy data centers to healthy ones as necessary to ensure that their Alarm executes. Single failures should resolve in under 30 seconds, while multiple failures may take slightly longer.</p><p>We achieve this by storing alarms in the same distributed datastore that backs the Durable Object storage API. This allows alarm reads and writes to behave identically to storage reads and writes and to be performed atomically with them, and ensures that alarms are replicated across multiple datacenters.</p><p>Within each data center capable of running Durable Objects, there are multiple processes responsible for tracking upcoming alarms and triggering them, providing fault tolerance and scalability within the data center. A single elected leader in each data center is responsible for detecting failure of other data centers and assigning responsibility of those alarms to healthy local processes in its own data center. In the event of leader failure, another leader will be elected and become responsible for executing Alarms in the data center. This allows us to guarantee at-least-once execution for all Alarms.</p>
    <div>
      <h3>How do I get started?</h3>
      <a href="#how-do-i-get-started">
        
      </a>
    </div>
    <p>Alarms are a great way to build new distributed primitives, like queues, atop Durable Objects. They also provide a method for guaranteeing work within a Durable Object will complete, without relying on a client request to “kick” the Object.</p><p>You can get started with Alarms now by enabling Durable Objects in the Cloudflare <a href="https://dash.cloudflare.com/">dashboard</a>. For more info, check the developer docs or jump in our Discord.</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Durable Objects]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Notifications]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5FKrh4z1ggyDYSTMgbDku6</guid>
            <dc:creator>Matt Alonso</dc:creator>
            <dc:creator>Greg McKeon</dc:creator>
        </item>
        <item>
            <title><![CDATA[Live Preview: Build and Test Workers Faster with Wrangler CLI 1.2.0]]></title>
            <link>https://blog.cloudflare.com/live-preview-build-and-test-workers-faster-with-wrangler-cli-1-2-0/</link>
            <pubDate>Mon, 19 Aug 2019 22:36:00 GMT</pubDate>
            <description><![CDATA[ As part of my internship on the Workers Developer Experience team, I set out to polish the Wrangler CLI for Cloudflare Workers. If you're not familiar with Workers, the premise is quite simple: Write a bit of Javascript that takes in an HTTP request, does some processing, and spits out a response.  ]]></description>
            <content:encoded><![CDATA[ <p>As part of my internship on the Workers Developer Experience team, I set out to polish the <a href="https://github.com/cloudflare/wrangler">Wrangler CLI</a> for <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>. If you're not familiar with Workers, the premise is quite simple: Write a bit of Javascript that takes in an HTTP request, does some processing, and spits out a response. The magic lies in where your Workers scripts run: on Cloudflare's edge network, which spans 193 cities in more than 90 countries. Workers can be used for nearly anything from configuring Cloudflare caching behavior to building entire serverless web applications. And, you don't have to worry about operations at <i>all.</i></p><p>I was excited to focus on Wrangler, because Wrangler aims to make developing and publishing Workers projects a pleasant experience for everyone, whether you're a solo dev working on the next big thing, or an engineer at a Fortune 100 enterprise. The whole point of serverless is about reducing friction, and Wrangler reflects that ethos.</p><p>However, when I started at Cloudflare in early June, some parts of the development experience still needed some love. While working on a new <a href="https://workers.cloudflare.com/docs/tutorials/build-a-rustwasm-function/">WASM tutorial</a> for the Workers documentation, I noticed a storm brewing in my browser…</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1weM15yKROpJCcZVqofQXu/f304b0cca5b5cd12baa4128819c6780f/image1.gif" />
            
            </figure><p>Wrangler lets you test your Workers project with a subcommand called <code>wrangler preview</code>, and every time I called it to test a new change it opened a new tab. Fast iteration is the most crucial part of a good developer experience, and while the preview was fast, things were getting messy. I was fighting my tooling, having to keep track of the latest preview tab every time I wanted to test a new change. I knew that if I was annoyed about this, others would be too.</p><p>So, I thought about what our customers wanted: similarity with tooling that they already used. I set out to create an experience inspired by `webpack-dev-server` and other similar watch-and-build tools, where you would have a single tab that would refresh live with your latest changes. However, I knew that getting changes into the Workers runtime to achieve this goal would be a tall order for week 2 of my internship, so I started thinking about solutions to send updates directly to the previewer.</p><p>Wrangler is written in <a href="https://www.rust-lang.org/">Rust</a>, so I was able to utilize the <a href="https://crates.io/">crates.io</a> ecosystem while developing this feature. I used the <a href="https://crates.io/crates/notify">notify</a> crate, which provides a cross-platform abstraction layer over the various file system event APIs provided by major OSes. However, there are some gotchas when implementing a file watcher that triggers a build and upload: you can’t simply trigger a build after every filesystem event, as a single file save can emit several events in quick succession depending on which editor you use! To prevent wasteful builds, I implemented a cooldown period, which only triggers the build process when no new file system events have been detected for at least 2 seconds. Rust’s rich standard library makes implementing concurrent behaviors like this very elegant:</p>
            <pre><code>/* rx.recv_timeout returns Ok if there was an event on the rx channel
 * or Err if the cooldown period has passed. The while let Ok(_) syntax
 * will end the loop if the cooldown period has ended, or restart the cooldown period if there was an event on the rx channel
 */
while let Ok(_) = rx.recv_timeout(cooldown) {
  message::working("Detected change during cooldown...");
}</code></pre>
            <p>Another challenge was handling communication with the previewer. I settled on an unconventional application of WebSockets, creating one to localhost to allow for a browser application to communicate with the Wrangler CLI running on the local machine. I coordinated with the Workers UI team to get my WebSocket client added to the preview UI, and with the security team to pass a security review for the feature, to make sure script contents were properly protected from exposure.</p><p>This was the result:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4BJCQTvxxCvz4yvGyc3IQs/d7e1ceed920b50caa1b240b934dc8b44/out_opt--1-.gif" />
            
            </figure><p>This is what Developer Experience is all about. You should feel like ??‍♀️??‍♂️ when using Wrangler, not like ?. <i>If this isn't the case, </i><a href="https://github.com/cloudflare/wrangler/issues/new/choose"><i>we want to hear about it</i></a><i>.</i></p><p>Live Preview was shipped in the <a href="https://github.com/cloudflare/wrangler/releases/tag/v1.2.0">1.2.0 release</a> of <a href="https://github.com/cloudflare/wrangler">Wrangler</a>, exposed under <code>wrangler preview --watch</code>. It works for all Wrangler projects, even ones that use WebAssembly.</p><p>And to the Workers Developer Experience team, Dubs, Ashley, Avery, Gabbi, Kristian, Sven, and Victoria: thank you. Y'all are motivated, talented, and I genuinely had fun every day this summer.</p> ]]></content:encoded>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[CLI]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">62c8xwr8Lc0wLybQfNLvnR</guid>
            <dc:creator>Matt Alonso</dc:creator>
        </item>
    </channel>
</rss>