Repository navigation
v3.9.0 — a window that stops where it says it stops
Fixes six defects in v3.8.0's own code, found by measuring it. Anyone on 3.8.0 should take this.
The event read walked the whole table
- Each of the two windows is
LIMIT 400, and aLIMITonly short-circuits if its window can fill. The kind lived onmonitors, so finding it needed a join, and a deployment with no grouped monitors — the default — could never fill the grouped side. - Every request to the page,
status.jsonand the feed scanned every event ever kept: 0.97 ms at 1,000 events, 6.96 ms at 50,000, 24.81 ms at 200,000. On D1 that isrows_read— about a dozen page views a day against the free tier's 5M. - The kind is on the event row now, with an index over
(grouped, at): 0.24 ms at every size, and the plan says SEARCH rather than SCAN. - A monitor written with
grouped = 2matched neither window and its history vanished from the page, the JSON and the feed.groupOfreads any non-zero as grouped; the windows now agree with it.
The body cap was set by the runtime, not by the constant
- Each chunk was enqueued before the total was checked, so the read overshot by one chunk: 112,561 bytes on undici, 69,489 on workerd, against a 65,536 cap. The chunk is cut now.
Latency measured the body
- An origin whose headers arrive in 3 ms and whose body takes a second reported 937 ms. That number is
latency_ms, the 24h sparkline anddays.ms_sum, so every deployment's chart took a permanent step at the v3.8.0 upgrade with nothing said about it. - It is time to the answer again. The body is still read; what reading it costs is not charged to the number you chart.
timeout had become unreachable
- The reason asked whether a status had arrived before it asked whether our own signal had fired, so a monitor that blew its timeout while the body trickled reported "answered, then stopped". Our deadline is ours: blaming the host for a budget it never saw is not an answer.
Tests for the features 3.8.0 was named for
- The cap,
incomplete, the two windows and agroupedvalue that is not 1 had no test. They do now, each verified by making the fix fail. - Three ratchets read the source for the mechanisms behind five releases of defects: a claim in prose the code does not keep, a rule kept on one surface and not its sibling, a remembered value whose invalidation misses a writer.
Also
/healthcarriesx-nabiz, the build answering. Nothing a deployment served said which version it was.- Telegram followed redirects; only the webhook had been fixed. A 3xx makes the POST a bodyless GET, answers 200, and the alert is gone.
- The 401 and 429 from a write carry CORS like the 201 and 400 beside them.
- The round warms the shaping, not only the database read — the first reader after each round was still paying a cost proportional to a group's hidden members.
llms.txtstill called the JSON, the feed and the badge uncached, three releases after they began reading through a held page.docs/api.mdcounted six endpoints above a table of seven, and/robots.txtwas in neither.
Upgrading
- A container adds the column, fills it and creates the index on start, and says so. On Cloudflare there are three statements in docs/UPGRADING.md — run in the order given.
- Check
expect_bodybefore pulling if it matches something late in a large page. Since v3.8.0 only the first 64 KB is read, so a monitor watching a footer goes down at the first round after the upgrade, with an alert, while the host is fine. The one-liner to check is in the upgrade notes.