pub struct Lease { /* private fields */ }Expand description
The lease this process holds. Dropping it removes the file (when the file is still this process’s), so a failed start never leaves a stale lease behind.
Implementations§
Source§impl Lease
impl Lease
Sourcepub fn started_at(&self) -> &str
pub fn started_at(&self) -> &str
When this process took the lease, RFC 3339: the identity of this server’s
generation, the same value the lease file carries as started_at.
Sourcepub fn keep_alive(&self)
pub fn keep_alive(&self)
Keep the lease young while the layer loads. A peer that finds a lease without a URL
waits for it only as long as the file is younger than BIND_GRACE; a cold start
that takes longer than that — a large layer, a machine under load — would otherwise
be taken for an abandoned one and taken over while its owner is still binding. So
until Lease::publish, a thread rewrites the same document every third of the
grace, under the lock publish also takes, so that a touch can never land after the
URL. It writes only while the file is still this process’s: a lease that was taken
over anyway is somebody else’s to write.
use majordomus_cli::lease::{elect, held, LeaseFile, Role};
use majordomus_cli::Repository;
let dir = tempfile::tempdir().unwrap();
std::fs::create_dir_all(dir.path().join(".ai/repo")).unwrap();
std::fs::write(dir.path().join(".ai/manifest.yaml"),
"schema: ai-repository/v1\nrepo:\n path: repo\nlocal:\n path: local\n tracked: false\n implicit_context: false\nsections:\n policy: repo/policy.yaml\n").unwrap();
let repo = Repository::discover(dir.path()).unwrap();
let Role::Server(lease) = elect(&repo).unwrap() else { panic!("nobody else serves a fresh directory") };
lease.keep_alive(); // returns at once; the touching runs beside the load
assert!(held().is_none(), "nothing is published yet");
lease.publish("http://127.0.0.1:1").unwrap(); // stops the touching, under the same lock
assert_eq!(held().unwrap().url.as_deref(), Some("http://127.0.0.1:1"));
assert!(matches!(LeaseFile::read(lease.path()), LeaseFile::Document(d) if d.url.is_some()));
lease.release();
assert_eq!(LeaseFile::read(&dir.path().join(".ai/local/state/mcp/server.json")), LeaseFile::Absent);Sourcepub fn publish(&self, url: &str) -> Result<(), Error>
pub fn publish(&self, url: &str) -> Result<(), Error>
Record the URL the server is listening on, atomically, so that a peer reading the file sees either no URL or the whole one. Refused when the file is no longer this process’s: a lease taken over while its owner was binding belongs to whoever took it, and writing over it would leave two servers claiming one address.
The document is written to a temporary file named for this lease’s token and synced
before anything else happens; then, under the lock every change to the lease takes
(take_over_with says why there is one), the file is checked to be still this
process’s and the temporary file is renamed over it. No take-over can land between
the check and the rename, and no other writer shares the temporary file.