Skip to main content

Module readings

Module readings 

Source
Expand description

The latest reading of a source, handed over at once.

CapabilityExecutor::execute answers a question: it runs the handler, or returns an answer byte-identical to what the handler would return (project.cache-is-invisible). A page a person is looking at asks for something else. It wants what is known now, at once, with how old that is, and it wants the answer to catch up behind it. That is a read, and it never passes itself off as an answer: a Latest always carries when it was read, whether the repository has moved since, and whether a newer reading is on its way.

§What a read costs

One lookup in this process’s memory. The handler, git and the file system are touched only by a worker of this module, off the path of the request:

  • The source was read in the repository as it is now. The reading is returned immediately. When it is older than REVALIDATE, a worker reads it again behind the caller, so a source the repository does not determine (health, the mesh, the forge) stays close to the present without any reader waiting for it.
  • The repository has moved since. A worker reads the source again and the caller waits for it for at most Patience::moved. A fast source is therefore current on the same request; a slow one is returned as it was, marked Freshness::Stale and refreshing. Every other source this process has been asked for lately is read again at the same moment, so the next screen a reader opens is ready before it is asked for.
  • The source has never been read here. There is nothing to hand over, so the caller waits for the first reading, for at most Patience::cold, and is told Freshness::Pending past that.

One worker reads a source at a time, however many callers ask. The readings to take wait in one queue, drained by at most WORKERS threads, so a change of the repository that sends every remembered source to be read again starts no more threads than that. A reading a caller is waiting for goes to the front of the queue and the ones nobody is waiting for go to the back, so a reader never waits behind the background. Under the workers the executor’s own cache and single flight still apply: a worker whose source did not change is answered from the cache and costs nearly nothing.

§Switching it off

MAJORDOMUS_CAPABILITY_CACHE=off makes every read run its handler and wait for it, as it makes every execute do. PATIENCE_SWITCH set to wait keeps the store and makes every read wait for a current reading, which is what a test that changes a repository and then reads a page needs in order to be exact.

§A reading, from first to known

use majordomus_cli::capability::readings::{read, Freshness, Patience};
use majordomus_cli::synthetic::SyntheticRepository;
use serde_json::json;

let repo = SyntheticRepository::small().unwrap();
let ctx = repo.context().unwrap();

// never read here: the caller waits for the first reading, and it is current
let first = read(&ctx, "plan.status", json!({}), Patience::WAIT);
assert_eq!(first.freshness, Freshness::Current);
assert!(first.value.is_ok() && first.read_at.is_some());

// known now: handed over from memory, with the age it has, and no handler runs for it
let ran = ctx.executor.handler_invocations();
let again = read(&ctx, "plan.status", json!({}), Patience::PAGE);
assert_eq!(again.value, first.value);
assert!(again.age.is_some() && !again.catching_up());
assert_eq!(ctx.executor.handler_invocations(), ran);

// a source that cannot answer is a reading that says why, never a missing one
let unknown = read(&ctx, "no.such.capability", json!({}), Patience::WAIT);
assert!(unknown.value.is_err());
assert_eq!(unknown.freshness, Freshness::Current);

Structs§

Latest
The latest reading of one source.
Patience
How long a read waits for a worker before it returns what it has.

Enums§

Freshness
How a reading stands against the repository as it is now.

Constants§

MAX_SOURCES
The most sources remembered at once; the one asked for longest ago is dropped first.
PATIENCE_SWITCH
The environment variable that sets how long a read waits: a number of milliseconds for a source whose repository has moved, or wait to wait for a current reading every time.
PENDING
What the first reading of a source says while it has not arrived.
REMEMBERED
How long a source nobody asked for is remembered, and so read again when the repository moves. A page left open asks for its sources every minute, so its sources stay; a screen nobody has looked at for five minutes stops costing anything when the repository changes.
REVALIDATE
How old a reading of the repository as it is now may grow before a worker reads its source again behind the caller.
WORKERS
How many sources are read at once by this module’s workers, all sources together.

Functions§

read
The latest reading of id asked with input: what this process knows now, returned within patience, with a worker reading the source again behind the caller whenever what is known is not current. See the module for what each case costs.