Building With Workers KV, a Fast Distributed Key-Value Store

Cloudflare Railgun is available when using Cloud Server Webuzo, Cloud Web Apps. Contact us to find out our latest offers!

In this example your authentication system will store a token when a user logs in. I’m using curl, but the backend code for your system is more likely to use whatever interface it has for making HTTPS requests. This request stores a blob of JSON identifying this token in a Worker KV namespace $NAMESPACE_ID with a key of $TOKEN_ID:

curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/$NAMESPACE_ID/values/$TOKEN_ID 
-X PUT 
-H "X-Auth-Key: $CLOUDFLARE_AUTH_KEY" 
-H "X-Auth-Email: $CLOUDFLARE_AUTH_EMAIL" 
-d '{
  "userId": "bob",
  "expires": "2018-07-11T03:44:12Z"
}'

Your Worker code, which runs on every request, will check if the token the user provides matches one you have stored. A single line of code (TOKEN_STORE.get()) pulls the JSON stored above from the Worker KV

addEventListener('fetch', event => {
 event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
 const token = request.headers.get('Authorization')
 if (!token)
   return new Response("An Authorization header is required", {status: 401})

 const tokenInfo = await TOKEN_STORE.get(token, "json")
 if (!tokenInfo)
   return new Response("Invalid token", {status: 403})
 
 if (Date.parse(tokenInfo.expires) < Date.now())
   return new Response(“Token expired”, {status: 403}) 

 request = new Request(request)
 request.headers.set("User-Id", tokenInfo.userId)
 return fetch(request)
}

A secure authentication system which adds virtually no latency at 1/7th the cost of Amazon API Gateway (with so much more flexibility and power)!

Dynamic Data

Traditionally you’ve had to decide between showing a super fast static site to your visitors, or being able to include dynamic data customizing your site for each visitor. That customization could be showing different products based on the customer’s profile, A/B testing site variants, or even including the customer’s current shopping cart and account information. Rather than waiting for this information to be served from a central database, it’s now possible to store it close to every visitor, delivering a custom page as quickly as you could a static resource.

For example, let’s say we have translations of our site stored as JSON in the KV store. We can dynamically insert this translation data as Javascript into the HTML of our site. In this example our site has a block which looks like this:


 
   
 

 ...

Our worker replaces that text with the content of our translations. You could alternatively use a Javascript templating engine or parse the content of the page to do something like Server-Side Includes.

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const token = request.headers.get('Authorization')


  const translationsPromise = TRANSLATION_DATA.get(country)
  const response = await fetch(request)
  const translations = await translationsPromise

  let newBody = await response.text()
  const ct = response.headers.get('content-type')
  if (ct.startsWith('text/html') && response.status === 200){
    newBody = newBody.replace('TRANSLATION DATA HERE', translations)
  }

  return new Response(newBody, response)
}

Workers is a full programming environment, meaning this is just the beginning. We have customers rendering their entire React App inside Workers, fully bootstrapping the data required to render their site.

Configuration

The Workers KV store creates a powerful way to configure your running Workers without having to redeploy them. You might want to implement feature flags to enable or disable features at will, or to dynamically update the data your code uses to make decisions. Workers deploy in under 30 seconds, but it’s common to have more data than can easily fit in Worker code. For example, we have customers interested in using Workers KV to block messages from lost or stolen IoT devices before they ever reach their origin:

addEventListener('fetch', event => {
 event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
 const deviceId = request.headers.get('device-id')
 const bannedEntry = await BANNED_DEVICES.get(deviceId)
 if (bannedEntry !== null){
   return new Response("This device has been banned", {status: 403})
 }

 return fetch(request)
}

Cloud Functions

One thing we’re excited about when we think about the Workers KV store is the potential for building beyond web applications. There are many situations where developers are looking for an easy way to execute code without worrying about provisioning or maintaining infrastructure. One of the most common cases we see is joining systems together.

For example, one of our customers is planning on using Workers KV to connect their Point of Sale system with their Delivery Service’s API:

// The endpoint we have bound this to is polled periodically
addEventListener('fetch', event => {
 event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
 const orderResp = await fetch(`https://api.pos-system.com/orders/active`, {
   headers: {
     'Authorization': 'POS_API_KEY'
   }
 })

 const orders = await orderResp.json()

 for (var i=0; i < orders.length; i++){
   let order = orders[i]

   const syncedData = await SYNCED_ORDERS.get(order.id, "json")

   // If the order data is newer than the last data we sent to the delivery company,
   // update it.
   if (syncedData.modifiedAt < order.modifiedAt) {
     await fetch(`https://api.delivery-system.com/orders/${ order.id }`, {
       method: 'POST',
       body: JSON.stringify(order),
       headers: {
         'Content-Type': 'application/json',
         'Authorization': 'DELIVERY_API_KEY'
       }
     })

     await SYNCED_ORDERS.put(order.id, JSON.stringify(order))
   }
 }

 return new Response("?")
}

Limits and Pricing

Workers KV is launching today in a limited beta. As we get feedback and operational experience we will be relaxing our storage limits and granting access to more users. While we may have more restrictive limits during beta, you can design your applications around the following characteristics:

  • Up to 1 billion keys per namespace
  • Keys of up to 2 kB
  • Values of up to 64 kB
  • Eventually consistent, global consistency within 10 seconds
  • 100k+ reads per second per key
  • Up to one write per second per key

We worked hard to make the pricing of Workers KV easy to understand and affordable for virtually any use case. Your $5 monthly Workers compute minimum includes 1 GB of KV storage and up to 10 million KV reads. If you use less than the 10 million included Worker requests now, you can use KV without paying a single cent more.

Beyond the minimums, Workers KV is billed at $0.50 per GB-month of additional storage and $0.50 per million additional KV reads.

To get beta access sign up here, we can’t wait to see what you build!

Subscribe to the blog for daily updates on all of our announcements.

Building With Workers KV, a Fast Distributed Key-Value Store
Cloudflare Railgun is available when using Cloud Server Webuzo, Cloud Web Apps. Contact us to find out our latest offers!

Comments are closed.