Make pending assignments safe to race, settle them on a tick, and say only what was checked
Review of #150: a withdrawal could land between the look and the act, a failed ask read as a build in flight, a request kept the wrong asker, a build being registered read as not built, build "true" could ask a build nothing waited on, and a status read changed state. Claim a row under the machine's hold before making it, keep a request only once asked, settle on the controller's own tick, raise an assignment not made as a condition until it is answered, and tie each row to its machine.
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
-- An assignment waits for its module's build (novox/hq issue 325).
|
||||
-- An assignment waits for its module's build (novox/hq issue 325, ADR 0261).
|
||||
--
|
||||
-- A merge that adds a module asks for its build (issue 300), and the module is registered when the build's
|
||||
-- outcome is taken in, minutes later. An `assign` in between was answered "no module of that name", which
|
||||
-- read as "nobody registered it". The controller now keeps every build it asks for, so `assign` can tell a
|
||||
-- build in flight from a module it never heard of, and an assignment made while the build runs is kept as
|
||||
-- pending and made when the build registers the module, or ended with the reason when it does not.
|
||||
-- pending and made by the controller when the build registers the module, or ended with the reason.
|
||||
|
||||
-- Every build the controller asked for, whatever asked it: a merge, a plan's tier, a person's `build`, an
|
||||
-- `assign` with build. Its outcome is the `build` row of the same id, written when the outcome is taken in;
|
||||
-- an ask without one is still running, or was lost. not_asked is why a merge's ask of a new module could
|
||||
-- not be made, and the id is then not a build's.
|
||||
-- Every build the controller asked for: a merge's new module, a plan's tier, a person's `build`, an `assign`
|
||||
-- with build. Kept once the ask is made, never before. Its outcome is the `build` row of the same id;
|
||||
-- an ask without one is still running, or was lost. not_asked is why the ask could not be made or waited
|
||||
-- for; for a merge that could not ask, the id is the controller's and no build's.
|
||||
create table build_request (
|
||||
id text primary key,
|
||||
repository text not null,
|
||||
@@ -23,20 +23,27 @@ create table build_request (
|
||||
);
|
||||
create index build_request_asked_at on build_request (asked_at);
|
||||
|
||||
-- An assignment kept until its module is registered. waiting until the build registers the module, then
|
||||
-- applied (the assignment was made), refused (the assignment was refused then, with the refusal), expired
|
||||
-- (the build failed, was not registered, or said nothing within its bound) or withdrawn (`unassign`).
|
||||
-- An assignment kept until its module is registered (ADR 0261). waiting until the build registers the
|
||||
-- module; applying while the controller makes it, under the machine's hold; then applied, refused (the
|
||||
-- assignment was refused then), expired (the build failed, was not registered, or said nothing within its
|
||||
-- bound) or withdrawn (`unassign`). raised_at is when an expiry or refusal was raised as a condition,
|
||||
-- acknowledged_at when a person took it back with `unassign`, cleared_at when its condition was cleared.
|
||||
-- Gone with its machine. Ended rows are deleted after 30 days.
|
||||
create table pending_assignment (
|
||||
id bigserial primary key,
|
||||
node text not null,
|
||||
module text not null,
|
||||
build_id text not null,
|
||||
repository text not null default '',
|
||||
source_path text not null default '',
|
||||
since timestamptz not null default now(),
|
||||
state text not null default 'waiting'
|
||||
check (state in ('waiting', 'applied', 'refused', 'expired', 'withdrawn')),
|
||||
note text not null default '',
|
||||
settled_at timestamptz
|
||||
id bigserial primary key,
|
||||
node uuid not null references node (id) on delete cascade,
|
||||
module text not null,
|
||||
build_id text not null,
|
||||
repository text not null default '',
|
||||
source_path text not null default '',
|
||||
since timestamptz not null default now(),
|
||||
state text not null default 'waiting'
|
||||
check (state in ('waiting', 'applying', 'applied', 'refused', 'expired', 'withdrawn')),
|
||||
note text not null default '',
|
||||
settled_at timestamptz,
|
||||
raised_at timestamptz,
|
||||
acknowledged_at timestamptz,
|
||||
cleared_at timestamptz
|
||||
);
|
||||
create unique index pending_assignment_waiting on pending_assignment (node, module) where state = 'waiting';
|
||||
create unique index pending_assignment_open on pending_assignment (node, module)
|
||||
where state in ('waiting', 'applying');
|
||||
|
||||
Reference in New Issue
Block a user