Cache Reference

January 20, 2026 ยท View on GitHub

The cache module provides simple and transactional caching APIs.

Module Functions

lookup

pub fn lookup(key: []const u8, options: LookupOptions) !CacheEntry

Look up an entry in the cache.

const cache = zigly.cache;

var entry = try cache.lookup("my-key", .{});
defer entry.close() catch {};

const state = try entry.getState();
if (state.isUsable()) {
    var body = try entry.getBody(null);
    // Read cached data
}

insert

pub fn insert(key: []const u8, options: WriteOptions) !Body

Insert a new cache entry. Returns a body to write content to.

var body = try cache.insert("my-key", .{
    .max_age_ns = cache.secondsToNs(3600),
});
try body.writeAll("cached content");
try body.close();

transactionLookup

pub fn transactionLookup(key: []const u8, options: LookupOptions) !Transaction

Transactional cache lookup. Prevents cache stampedes by allowing only one request to populate a missing entry.

var tx = try cache.transactionLookup("my-key", .{});
defer tx.close() catch {};

const state = try tx.getState();
if (state.mustInsertOrUpdate()) {
    // We're responsible for populating the cache
    var result = try tx.insert(.{ .max_age_ns = cache.secondsToNs(300) });
    try result.body.writeAll("new data");
    try result.body.close();
}

transactionLookupAsync

pub fn transactionLookupAsync(key: []const u8, options: LookupOptions) !BusyHandle

Async transactional lookup. Returns immediately with a handle to wait on.

var busy = try cache.transactionLookupAsync("key", .{});
// Do other work...
var tx = try busy.wait();

replace

pub fn replace(key: []const u8, options: ReplaceOptions) !ReplaceHandle

Atomically replace a cache entry.

var handle = try cache.replace("key", .{});
var body = try handle.insert(.{ .max_age_ns = cache.secondsToNs(300) });
try body.writeAll("new content");
try body.close();

Time Helpers

secondsToNs

pub fn secondsToNs(seconds: u64) u64

Convert seconds to nanoseconds.

const ttl = cache.secondsToNs(3600);  // 1 hour in nanoseconds

msToNs

pub fn msToNs(ms: u64) u64

Convert milliseconds to nanoseconds.

const delay = cache.msToNs(500);  // 500ms in nanoseconds

Constants

pub const seconds_per_ns: u64 = 1_000_000_000;
pub const ms_per_ns: u64 = 1_000_000;

WriteOptions

Configuration for cache writes.

pub const WriteOptions = struct {
    max_age_ns: u64 = 0,                    // Required: TTL
    initial_age_ns: ?u64 = null,            // Initial age of the entry
    stale_while_revalidate_ns: ?u64 = null, // Serve stale period
    surrogate_keys: ?[]const u8 = null,     // Space-separated keys for purging
    length: ?u64 = null,                    // Known content length
    user_metadata: ?[]const u8 = null,      // Custom metadata
    sensitive_data: bool = false,           // PCI compliance flag
    vary_rule: ?[]const u8 = null,          // Vary rule
    edge_max_age_ns: ?u64 = null,           // Edge-only TTL
};

Example

var body = try cache.insert("key", .{
    .max_age_ns = cache.secondsToNs(300),
    .stale_while_revalidate_ns = cache.secondsToNs(60),
    .surrogate_keys = "product-123 category-electronics",
    .user_metadata = "version=2",
});

LookupOptions

Configuration for cache lookups.

pub const LookupOptions = struct {
    request_headers: ?wasm.RequestHandle = null,
};

Typically used with default values:

var entry = try cache.lookup("key", .{});

LookupState

State of a cache entry.

Methods

isFound

pub fn isFound(self: LookupState) bool

Entry exists in cache (may be stale).

isUsable

pub fn isUsable(self: LookupState) bool

Entry can be served to clients.

isStale

pub fn isStale(self: LookupState) bool

Entry is past its TTL but within stale-while-revalidate window.

mustInsertOrUpdate

pub fn mustInsertOrUpdate(self: LookupState) bool

For transactions: this request must populate the cache.

Example

const state = try entry.getState();

if (!state.isFound()) {
    // Not in cache
} else if (state.isStale()) {
    // Stale but usable, consider revalidating
} else if (state.isUsable()) {
    // Fresh cache hit
}

CacheEntry

A cache entry from a non-transactional lookup.

Methods

getState

pub fn getState(self: CacheEntry) !LookupState

Get the entry state.

getBody

pub fn getBody(self: CacheEntry, range: ?BodyRange) !Body

Get the entry body. Pass null for full content or a BodyRange for partial.

// Full content
var body = try entry.getBody(null);

// Partial content (bytes 0-99)
var partial = try entry.getBody(.{ .from = 0, .to = 100 });

getUserMetadata

pub fn getUserMetadata(self: CacheEntry, allocator: Allocator) ![]u8

Get custom metadata stored with the entry.

getLength

pub fn getLength(self: CacheEntry) !u64

Get content length in bytes.

getMaxAgeNs

pub fn getMaxAgeNs(self: CacheEntry) !u64

Get the TTL in nanoseconds.

getStaleWhileRevalidateNs

pub fn getStaleWhileRevalidateNs(self: CacheEntry) !u64

Get the stale-while-revalidate period.

getAgeNs

pub fn getAgeNs(self: CacheEntry) !u64

Get the current age of the entry.

getHits

pub fn getHits(self: CacheEntry) !u64

Get the number of times this entry has been served.

close

pub fn close(self: *CacheEntry) !void

Close the cache entry.


Transaction

A transactional cache handle for request-collapsing.

Methods

All CacheEntry methods, plus:

insert

pub fn insert(self: *Transaction, options: WriteOptions) !InsertResult

Insert content into the cache.

var result = try tx.insert(.{
    .max_age_ns = cache.secondsToNs(300),
});
try result.body.writeAll("cached content");
try result.body.close();

Returns InsertResult with a body field.

insertAndStreamBack

pub fn insertAndStreamBack(self: *Transaction, options: WriteOptions) !InsertAndStreamBackResult

Insert and get a readable handle to the inserted content.

var result = try tx.insertAndStreamBack(.{
    .max_age_ns = cache.secondsToNs(300),
});
try result.body.writeAll("content");
try result.body.close();

// Read back what we just inserted
var cached = try result.entry.getBody(null);
const data = try cached.readAll(allocator, 0);

Returns InsertAndStreamBackResult with body and entry fields.

update

pub fn update(self: *Transaction, options: WriteOptions) !void

Update metadata without changing the body.

try tx.update(.{
    .max_age_ns = cache.secondsToNs(600),  // Extend TTL
});

cancel

pub fn cancel(self: *Transaction) !void

Cancel the transaction without inserting.


BusyHandle

Handle for async cache lookups.

Methods

wait

pub fn wait(self: *BusyHandle) !Transaction

Wait for the lookup to complete.

close

pub fn close(self: *BusyHandle) !void

Close without waiting.


ReplaceHandle

Handle for atomic cache replacement.

Methods

All CacheEntry methods for reading the existing entry, plus:

insert

pub fn insert(self: *ReplaceHandle, options: WriteOptions) !Body

Insert the replacement content.


BodyRange

Range for partial content reads.

pub const BodyRange = struct {
    from: u64 = 0,
    to: u64 = 0,
};

Example

// Read bytes 1000-1999
var body = try entry.getBody(.{ .from = 1000, .to = 2000 });

ReplaceOptions

Options for cache replacement.

pub const ReplaceOptions = struct {
    request_headers: ?wasm.RequestHandle = null,
};