Skip to content

hyper Cache Service โ€‹

A hyper Cache service is a simple key-value store, where the key is a unique string and the value is a JSON document.

This service keeps caching simple giving you a pattern matcher query to return a filtered set of values, or you can retrieve directly by key.

Features โ€‹

  • ttl: Time-To-Live to specify how long to cache a document, such as 3 minutes, 3 hours, or 3 days.

  • query: Using simple pattern matching, request a batch of keys and values. This feature gives you the ability to pull a batch of keys and values in one request.

Why Cache? โ€‹

The primary purpose of a cache is to provide fast and inexpensive access to copies of data. Most applications will have hotspots in its persisted data, data that is accessed more frequently than others, and seldomly updated.

By caching those hotspots, the application can be made more performant and load can be removed from the primary database.

Additionally, some database queries are especially expensive to perform. An example is queries that involve multiple round trips (or worse JOINs), or queries with intensive calculations.

By caching such query results, you pay the price of the query, or intensive calculations only once. Then you can quickly retrieve the data multiple times without having to re-execute the query or re-perform the intensive calculation.

Use Cases โ€‹

Fast Document Retrievals โ€‹

When your application is performing a high volume of reads on the database, one way to keep your database from being overloaded with requests is to cache heavily requested documents. You can then use the cache to read the documents. With this pattern, the cache will be continually updated with the most recent documents, you would then write to the cache once a document was successfully created on the datastore, and then client requests would check the cache before checking the datastore for documents.

INFO

Your cache key does not have to be the same as your document key. Use the cache key to create fast pattern queries on your documents.

Instead of running the same query for the same list of documents against your database, you could pull this data from the cache, instead. This takes the stress off of your database.

For example, if you name your key the combination of the document type and the document _id, then you could query your cache for all of the documents of a given type, keeping the stress off of your database.

Aggregate Metrics โ€‹

Caches are great for counts and other aggregates such as mean, median, min, max, standard deviation, etc. By storing aggregates in the cache, you reduce the need to perform complex queries against the database. You can proactively update the count or sum in the cache after the data is stored in the database. When a request comes in, retrieve the value from the cache. If the value does not reside in the cache, then run the expensive query to get the value and post it to the cache for next time.

INFO

Depending on your use cases, you might find it valuable to seed the cache during off-hours by running queries and caching their results.

A good seeding strategy requires that you know when cache hits occur to ensure the cached data is as fresh as possible.

Create a Cache Service โ€‹

Create a hyper Cache Service in the hyper Domain.

js
import { connect } from "hyper-connect";

const { cache } = connect(process.env.HYPER);

await cache.create(); // { ok: true }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X PUT https://$HOST/cache/$DOMAIN

Common Responses โ€‹

StatusDescriptionResponse
201The Cache Service was created{ ok: true }
409The Cache Service already exists{ ok: false, status: 409 }

Destroy a Cache Service โ€‹

Destroy a hyper Cache Service in the hyper Domain. This will remove all key-value pairs stored in the Cache Service.

DANGER

This is a destructive operation that will destroy the Cache Service and all key-value pairs stored within it. Be really sure you want to do this, before destroying your Cache Service.

js
import { connect } from "hyper-connect";

const { cache } = connect(process.env.HYPER);

await cache.destroy(true); // { ok: true }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X DELETE https://$HOST/cache/$DOMAIN

Common Responses โ€‹

StatusDescriptionResponse
200The Cache Service was destroyed{ ok: true }
404The Cache Service does not exist{ ok: false, status: 404 }

Cache a Document โ€‹

Store a Document in the Cache Service at the specified key

INFO

Use a schema validation library like Zod to verify documents are the shape your business logic expects, prior to caching in your hyper Cache Service.

js
import { connect } from 'hyper-connect'

const { cache } = connect(process.env.HYPER)

await cache.add('movie-1', { _id: "...", ... }, '2h') // { ok: true }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X POST https://$HOST/cache/$DOMAIN
 -H 'Content-Type: application/json' \
 -d '{ "key": "movie-1", "value": { "_id": "...", "title": "Ghostbusters", "year": "1984", "type": "movie" }, "ttl": "2h" }'

Input โ€‹

FieldType [optional]Description
keystringThe key to store the document at
valueobjectThe document to be stored
ttl[string]The Time-To-Live for the cached value. If not provided, then the value is cached indefinitely

ttl Format โ€‹

The ttl provided should follow the format XY where X is a number, and Y is a single character representing a unit of time:

s: secondsm: minutesh: hoursd: daysw: weeksy: years

Eg. 10s, 15m, 5h, 2d, 1w, 1y

Common Responses โ€‹

StatusDescriptionResponse
201The document was created{ ok: true }
404The Cache Service does not exist{ ok: false, status: 404 }
409A document stored at the key already exists{ ok: false, status: 409 }

Retrieve a Document โ€‹

Retrieve a Document in the Cache Service at the specified key

js
import { connect } from "hyper-connect";

const { cache } = connect(process.env.HYPER);

await cache.get("movie-1"); // { ok: true, doc: {...} }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X GET https://$HOST/cache/$DOMAIN/movie-1

Common Responses โ€‹

StatusDescriptionResponse
201The document was retrieved{ ok: true, doc: {...} }
404A document stored at the key does not exist or the Cache Service does not exist{ ok: false, status: 404 }

Replace a Document โ€‹

Replace a Document in the Cache Service at the specified key. This operation REPLACES the document, so the entire document must be provided.

js
import { connect } from 'hyper-connect'

const { cache } = connect(process.env.HYPER)

await cache.set('movie-1', { _id: "...", ... }, '2h') // { ok: true }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X PUT https://$HOST/cache/$DOMAIN/movie-1?ttl=2h
 -H 'Content-Type: application/json' \
 -d '{ "_id": "...", "title": "Ghostbusters", "year": "1984", "type": "movie" }'

See ttl Format on how to format the ttl if provided.

Common Responses โ€‹

StatusDescriptionResponse
200The document was replaced{ ok: true }
404The Cache Service does not exist{ ok: false, status: 404 }

Remove a Document โ€‹

Remove a Document in the Cache Service at the specified key.

js
import { connect } from "hyper-connect";

const { cache } = connect(process.env.HYPER);

await cache.remove("movie-1"); // { ok: true }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X DELETE https://$HOST/cache/$DOMAIN/movie-1

Common Responses โ€‹

StatusDescriptionResponse
200The document was removed{ ok: true }
404A document stored at the key does not exist or the Cache Service does not exist{ ok: false, status: 404 }

Query a Cache Service โ€‹

Query the Cache Service for all key-value pairs, whose key matches the provided pattern. Using the * wildcard, you can define patterns that match all the key-values that either start with the provided pattern, end with the pattern, or is in-between the pattern.

For example movie-*, *-1984, or movie*1984

INFO

Remember, you Cache Service keys do not need to be strictly _id from a hyper Data Service. They can be anything! You can store more information in your keys, such that a pattern can fetch multiple cached documents in a single request.

js
import { connect } from "hyper-connect";

const { cache } = connect(process.env.HYPER);

await cache.query("movie*"); // { ok: true, docs: [ { key: 'movie-5', value: {...} } ] }
sh
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X POST|GET https://$HOST/cache/$DOMAIN/_query?pattern=movie*

Common Responses โ€‹

StatusDescriptionResponse
200The query was successful{ ok: true, docs: [ { key: 'movie-5', value: {...} } ]}
404The Cache Service does not exist{ ok: false, status: 404 }