Skip to content
hekla

Try it

A running process, not a recording.

One hekla instance, on the open internet, serving the console that ships inside the binary. The log is real, the read models are real, and the commands you send are appended to the same log everyone else is reading.

The movement you will see in it is generated: a script subscribes and unsubscribes 10 students of its own among 6 courses of its own, so the log and the projector positions are never sitting still. The 6 courses listed below are the ones it never touches.

01What you are looking at

Shared, and wiped every half hour.

It runs the courses project, the one on the Dynamic Consistency Boundary page. The Subscribe command shown there is the command running here, read from the same directory this site is built from.

Every 30 minutes the data directory is deleted and seeded again. Whatever you write lasts until then, and so does whatever anyone else writes.

Nothing here is a fixture. The seat counts you read came out of the log, the traces are chains the runtime recorded, and a refused command is refused by the same code you can run on your own machine in a minute.

02Something to do with it

Take the last seat.

Open the console, go to Commands, and run Subscribe with one of the course ids and one of the student ids below. They are registered already.

Concurrency seats 2, so 2 different students fill it and the next one back is course_is_full. Send the same student twice instead and you get already_subscribed, which is a different rule and is checked first. Then look at that course on Events: neither refusal is there, because a refused command appends nothing.

the same thing without the console
$ C=0190d1a1-0000-7000-8000-00000000c00a$ curl -sX POST https://demo.hekla.tqwewe.com/commands/Subscribe -H 'content-type: application/json' -d "{\"course_id\":\"$C\",\"student_id\":\"0190d1a1-0000-7000-8000-000000000001\"}"{"causation_id":"...","correlation_id":"...", "events":[{"tags":["course_id:...","student_id:...0001"],"type":"student.subscribed"}], "positions":{"first":214,"last":214}}$ curl -sX POST https://demo.hekla.tqwewe.com/commands/Subscribe -H 'content-type: application/json' -d "{\"course_id\":\"$C\",\"student_id\":\"0190d1a1-0000-7000-8000-000000000003\"}"{"causation_id":"...","correlation_id":"...", "error":{"code":"course_is_full","message":"that course has no seats left"}}

Cryptography

0190d1a1-0000-7000-8000-00000000c007

seats 3

GraphTheory

0190d1a1-0000-7000-8000-00000000c008

seats 5

TypeTheory

0190d1a1-0000-7000-8000-00000000c009

seats 8

Concurrency

0190d1a1-0000-7000-8000-00000000c00a

seats 2

InformationRetrieval

0190d1a1-0000-7000-8000-00000000c00b

seats 12

MachineLearning

0190d1a1-0000-7000-8000-00000000c00c

seats 20

Students the seed registered

  • 0190d1a1-0000-7000-8000-000000000001
  • 0190d1a1-0000-7000-8000-000000000002
  • 0190d1a1-0000-7000-8000-000000000003
  • 0190d1a1-0000-7000-8000-000000000004
  • 0190d1a1-0000-7000-8000-000000000005
  • 0190d1a1-0000-7000-8000-000000000006
03How it is exposed

The bind address is still the boundary.

Nothing in hekla is authenticated, and this instance is no exception. It listens on loopback, exactly as it does on your machine, and a proxy in front of it is what decides which requests reach the port at all: every GET but the scrape, and POST to a command. Everything else is refused before it arrives.

That is the deployment story the documentation gives, run as written. Only an effect calls out, and this project declares none, so there is no path from a request here to a socket anywhere else.

POST /projectors/{name}/replay

Rebuilds a read model from position zero. Cheap here, and free to anyone who asks.

POST /effects/{name}/skip/{position}

Abandons an event permanently. This project declares no effects, so there is nothing to skip.

GET /metrics

The scrape. An operator surface rather than a visitor one, and the only GET refused.

Requests are rate limited per address, reads more generously than writes, under a second limit across every caller at once. A limit answers 429, which is distinguishable from the 503 a read model answers while it is catching up.