-
v0.0.7
StableGates / package (push) Successful in 41sGates / test (push) Successful in 1m35sGates / test-aarch64 (push) Successful in 6m48sGates / frontend (push) Successful in 1m22sGates / container (push) Successful in 9sCI / gates (push) Successful in 23m18sGates / frontend (push) Successful in 1m8sGates / package (push) Successful in 40sRelease / guard (push) Successful in 17sGates / test (push) Successful in 1m35sGates / test-aarch64 (push) Successful in 6m55sGates / container (push) Successful in 9sRelease / gates (push) Successful in 9m23sRelease / publish (push) Successful in 4m26sreleased this
2026-08-20 21:24:12 +00:00 | 67 commits to master since this releaseOperational failures get a page of their own, and the query log stops wearing out the disk it lives on: the deployed Pi was writing half a gigabyte a day to store two megabytes of query rows, one transaction per query. Both came out of running 0.0.6 on real hardware.
Added
- A diagnostics page. Operational failures now land in one curated log instead of only journald: blocklist download failures, certificate reload failures, disk pressure, query-log writer and maintenance failures, upstream exchange and history failures, client tracking failures, listener and configuration problems at boot, and the query-log recreation an upgrade causes. One entry per failing subject — an entry opens on the first failure, counts repeats, and closes itself when the subject recovers; nothing needs dismissing. Each entry says what it means for the service and what to do about it.
GET /api/diagnosticsserves the log,GET /api/healthreports the active counts and degrades while the diagnostics store itself cannot write, and/metricsgainsnxdns_diagnostics_active_warnings,nxdns_diagnostics_active_errorsandnxdns_diagnostics_write_failures_total. Resolved entries can be purged when you decide the history has served its purpose — one entry from its row or its detail page, or the whole resolved history at once with "Purge all resolved" (DELETE /api/diagnostics/{id}andDELETE /api/diagnostics). An entry that is still failing is the current state of the box, not history, so it has no purge action and the API answers 409.
Changed
- The query log commits once a minute instead of once a query. The writer batched for 100 milliseconds, which at a household's query rate means almost every query got a transaction of its own — and a transaction costs the disk far more than the row it carries. On the deployed Pi that came to roughly 0.5 GiB of writes a day to store 2.3 MB of query rows, the kind of write volume that kills an SD card. The batch window is now
logging.query_log_flush_interval_s: 60 seconds by default (the same minute Pi-hole'sDBintervaldefaults to, for the same reason), anything from 0 to 3600, editable on the settings page. Batches are still capped at 100 rows, so a burst is committed as soon as it fills one rather than waiting out the window, and the in-memory queue, its drop-oldest backpressure and retention are untouched. The price is two kinds of lag: a crash costs about one interval of query history — more if the writer was held back by a full disk or a slow write — and every query-log-backed view — the query-log page, the dashboard totals, the timeseries — is about one interval behind. The live page is not affected; it is fed before the queue. Set the key to0for the old write-immediately behavior.
Fixed
- Shutdown no longer races the last query rows to the disk. The query-log writer was stopped by the same cancellation that stopped the DNS listeners, so whether the batch it was holding reached the database depended on which happened to land first, the cancellation or the queue closing. Shutdown now stops and joins the listeners and every other query producer first, then closes the queue, then waits for the writer to finish emptying it — the held batch and everything still queued get written. If free space is below the critical threshold and the disk monitor will not let that final write through, the rows are counted as dropped instead of holding the exit open indefinitely.
- An upstream success rate no longer rounds up to 100.0% while failures stand. One decimal place cannot hold 12,696 successes out of 12,698 attempts: it rounded to
100.0%, so the row claimed perfect reliability next to a failure count of 2. Neither end of the scale is reachable by rounding any more —100.0%needs an actual absence of failures and0.0%an actual absence of successes, and a rate a hair off either end shows99.9%or0.1%instead. - A query log set aside by a schema change is no longer named
corrupt. Every recreate wrote the old file toquerylog.db.corrupt-<unix seconds>, whatever sent it there — including the fingerprint mismatch an upgrade causes, where the file is a healthy database this build simply cannot read. The name is the only account of the reason that outlives the log line, so it read as an accusation and invited operators to delete an intact file. The name now says which of the four cases it hit:querylog.db.corrupt-…,.not-a-database-…,.quick-check-failed-…or.schema-changed-…. The 0.0.6 upgrade producesschema-changed. Nothing else about the recreate changed, and no existing aside file is renamed.
Artifacts
0df1353252a817e929438b5e6c1bf8c58be7862c0b46dc7ef167752177f6a2c0 nxdns-0.0.7-x86_64-linux-musl.tar.gz 368d51d30ea2ec3721786c7ea973440827b1dadc54e16d01612e36670dfec3db nxdns-0.0.7-aarch64-linux-musl.tar.gz 7b2527ab6fcc0d16fe7cb9d5168961058e7fc4656f262d3adc17506f862166dc IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.7@sha256:28363f6a9a7add846cb21d5739c037d20be3df396d4c9b6a3e9f28f4c87e9ec3Commits since v0.0.6
324704b build: bump version to 0.0.7 addf24f query log batching: one transaction per flush interval, not per query 037f209 milestone 27: diagnostics — operational failures land in one curated log, resolved history purgeable 3dd8214 dashboard: a success rate never rounds up to 100.0% while failures stand 64c0d72 querylog: the aside file's name says why, so a schema change is not called corruptDownloads
- A diagnostics page. Operational failures now land in one curated log instead of only journald: blocklist download failures, certificate reload failures, disk pressure, query-log writer and maintenance failures, upstream exchange and history failures, client tracking failures, listener and configuration problems at boot, and the query-log recreation an upgrade causes. One entry per failing subject — an entry opens on the first failure, counts repeats, and closes itself when the subject recovers; nothing needs dismissing. Each entry says what it means for the service and what to do about it.