NAME
Langertha::Skeid::Registry - Signed Skeid-to-Skeid capacity snapshots: encoding, signing, verification, mapping
VERSION
version 0.003
SYNOPSIS
# downstream: what GET /skeid/registry/snapshot sends
my ($body, $signature) = Langertha::Skeid::Registry->signed_snapshot($skeid);
# fronting tier: what CapacityProbe::Registry does with it
Langertha::Skeid::Registry->verify($body, $signature, $secret) or die 'bad signature';
my $reading = Langertha::Skeid::Registry->reading_from_snapshot($snapshot, tags => ['local']);
DESCRIPTION
The two halves of the registry (ADR 0017) share one module, so the bytes one side signs are the bytes the other side checks and the mapping to a capacity reading is written down once.
The signature is sha256= plus the hex HMAC-SHA256 of the exact response body, in the "SIGNATURE_HEADER". generated_at and ttl sit inside the signed body, so a snapshot's age cannot be changed without breaking it.
SIGNATURE_HEADER
X-Skeid-Registry-Signature.
SCHEMA_VERSION
The snapshot schema this code writes and accepts: 1.
MIN_SECRET_BYTES
The shortest signing secret either side accepts: 32 bytes, the HMAC-SHA256 output size. A downstream with a shorter one fails its config load; a fronting probe with one reports missing_secret.
encode
my $body = Langertha::Skeid::Registry->encode($snapshot);
Canonical JSON bytes (sorted keys).
sign
my $signature = Langertha::Skeid::Registry->sign($body, $secret); # 'sha256=...'
sha256= plus the hex HMAC-SHA256 of $body under $secret.
signed_snapshot
my ($body, $signature) = Langertha::Skeid::Registry->signed_snapshot($skeid);
"registry_snapshot" in Langertha::Skeid, encoded and signed with the Skeid's registry_secret. Dies without a secret: a snapshot is never published unsigned.
verify
my $ok = Langertha::Skeid::Registry->verify($body, $signature_header, $secret);
True when the header is the signature of these exact bytes under this secret. The comparison takes the same time wherever the first difference is, so a caller cannot find the signature one character at a time.
reading_from_snapshot
my $reading = Langertha::Skeid::Registry->reading_from_snapshot($snapshot, tags => \@tags);
# { used => 5, limit => 16 } or { used => undef, limit => undef } (no ceiling)
Turns a verified snapshot into the one capacity reading admission consumes for the node that stands for this downstream. Over the downstream nodes that are healthy and carry every tag in tags:
freeper node ismax_conns - inflight, at mostlimit - usedof the node's own capacity reading when it has one with a limit, and 0 while its backoff is pending. Never below 0, never above the node's limit.limitis the sum of the nodes' limits (max_conns, or the reading's limit for a node without one),usedislimitminus the summedfree.A node with no ceiling at all (
max_conns0 and no limited reading) makes the whole downstream unbounded: the reading has no limit and does not narrow admission.No selected healthy node: reported as full (
used1 oflimit1). That downstream would answer503, so routing should go elsewhere.
used is the downstream's own number. It is never added to what this process counts in inflight: the requests this process sent are already in it (ADR 0017).
SEE ALSO
"registry_snapshot" in Langertha::Skeid and "registry_enabled" in Langertha::Skeid (publishing), Langertha::Skeid::CapacityProbe::Registry (reading), Langertha::Skeid::Secret
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha-skeid/issues.
IRC
Join #langertha on irc.perl.org or message Getty directly.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.