K2THE EVENT
STREAM LAB
Field guide ↗
CLOUDFLARE BIRTHDAY WEEK 2026 / K2 PUBLIC BETA

The log sits
between now
and next.

Producers and consumers should not have to arrive at the same time. K2 accepts ordered batches of bytes from the edge, retains them durably, and lets independent subscriptions advance on their own clocks.

LIVE SYSTEM MAP01 / PRODUCE
WORKERK2
K2
NOT A QUEUE · NOT A PIPELINE · NOT A SIMULATED LOGSCROLL TO EXPLORE ↓
01ATOMIC PRODUCER BATCH
24HTHIS STREAM'S RETENTION
02READER LANES / ACCESS NEEDED
REALWORKER-TO-K2 WRITES
01 / DATA FLOW

One write. Two timelines.

The arrows below are the architecture; the receipt in the live lab is real. Subscription lanes only become live when a scoped K2 Consume credential is installed—no fake read-back.

01 / INPUT

Your browser

Chooses a fixed synthetic event lifecycle. No customer data or arbitrary messages.

POST /api/produce
02 / ENCODE

Edge Worker

Assigns stable event IDs, encodes JSON as bytes, and calls the K2 producer binding.

env.EVENTS.send(records)
03 / APPEND

K2 durable log

Accepts or rejects the whole batch. K2 stores the ordered log on R2 internally.

bdayweek2026_k2_lab
WHEN CONFIGURED: THE SAME LOG, TWO INDEPENDENT CURSORS
04A / SUBSCRIPTION ALPHALease → validate → ackCursor A advances only when A acknowledges.
04B / SUBSCRIPTION BETALease → validate → ackCursor B advances independently of A.

The Worker producer is ready. Checking whether real subscription readers are configured…

THE PRODUCER'S ANSWER

A successful send() means K2 accepted all records atomically. The producer binding does not return offsets or a consumer acknowledgement. Our batch ID is assigned by this Worker, not by K2.

THE CONSUMER'S ANSWER

A real subscription requests a batch from K2's authenticated HTTP API, gets a five-minute lease, processes every record, and acknowledges the entire batch. A second subscription still has its own unread copy.

02 / INTERACTIVE WORKBENCH

Put bytes on the stream.

Pick an example, inspect its exact three-record template, then produce it through a real Worker binding. Nothing here purchases, publishes, or triggers a security rule in another app.

01 / DESIGN A BATCHFIXED SAFE EXAMPLES

Choose a lifecycle.

Loading K2 examples…

THE PAYLOAD SHAPETEMPLATE / BEFORE SENDING
Waiting for the example catalog…

The Worker adds fresh event UUIDs, an application batch ID, and a producer timestamp when you send. Only the three predefined records can be written.

02 / WRITE AT THE EDGECONNECTING

An atomic commit to K2.

One click creates one batch of three records. Either K2 accepts them all, or this page shows an error. A non-retryable error may have an unknown outcome, so the Worker does not retry on your behalf.

No batch has been sent yet. Inspect the template at left, then append it.
Inspect the actual accepted JSON records
No accepted batch yet.
03 / THE READ SIDE

Same events. Separate cursors.

Each lane uses its own real subscription—not a mirrored array from the producer response. If one reader acknowledges a batch, the other still has its own position. Public visitors share each subscription's cursor.

SUBSCRIPTION / ALPHACHECKING

Operations reader

Leases up to 10 K2 records, validates their lab schema, and acknowledges the whole batch after processing.

Waiting for a real subscription.
SUBSCRIPTION / BETACHECKING

Audit reader

Reads the same stream on an independent cursor. Duplicate event IDs must be handled idempotently.

Waiting for a real subscription.

Checking whether scoped K2 Consume credentials are configured. Nothing is simulated.

04 / DESIGN CONSTRAINTS

What the receipt does not tell you.

Durable acceptance, consumption, and processing are three different states. This lab labels them separately.

01 / ATOMIC BATCHES

All or nothing.

K2 accepts every record in a batch together. It stores bytes; your application decides what they mean. A producer success is not proof any reader has consumed an event.

02 / AT LEAST ONCE

Duplicates can happen.

If a lease expires or a batch is released, K2 can deliver it again. Producer retries with uncertain outcomes can also create duplicates. Use the event ID as an idempotency key.

03 / INDEPENDENT CURSORS

Read without deleting.

Each subscription receives the log independently. Acknowledging a batch advances only that subscription; the bytes stay in the stream until the one-day retention window ends.

04 / SECURITY BOUNDARY

No public stream endpoint.

HTTP production is disabled. Only the Worker binding can append, and this API permits small preset batches behind a rate limit. A K2 Consume token, when configured, stays in a Worker secret.

05 / UNDER THE HOOD

Readable primitives, real boundaries.

PRODUCER / RUNNING NOW
const records = events.map(event => ({
  content: new TextEncoder().encode(JSON.stringify(event)),
  headers: { "event-type": event.type }
}));
const result = await env.EVENTS.send(records);
if (!result.success) return failedBatch();

The binding authenticates on behalf of the Worker; it receives bytes, not strings or browser tokens.

CONSUMER / REQUIRES SCOPED TOKEN
POST /subscriptions/:id/consume
→ batch_id + records + lease expiry

validate every record → process the batch
POST /subscriptions/:id/batches/:batch_id/ack

There is no read binding in this launch. Subscription HTTP requests use a server-side K2 Consume credential, never JavaScript delivered to your browser.