On 2026-10-09 a release's gate on the control node read the machine's
report against a newer send another plan had just made there, failed
three builds the machine had reported healthy, and put them back on
every machine to a controller older than the store's schema; that
controller then passed the newer plan's gate from its own health.
- A gate keeps what its send carried (digest, sequence) and reads the
report against it; a report on the last send is on it too.
- A gate judges only the build the machine was last sent: another build
there supersedes the judging — no verdict, nothing put back.
- A controller is told its build (MESH_CONTROLLER_VERSION, ${version}
in a process's env) and records how far it reads the store's schema;
a put-back to a build that reaches less, or never said, is refused
and the current build kept, said as urgent.
- A release's open gate holds other sends of its modules there, and a
plan's own first send waits on it.
48 lines
1.7 KiB
Go
48 lines
1.7 KiB
Go
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
// What a controller build knows of the store's schema (novox/hq issue 352): the highest migration it
|
|
// carries, recorded by its version when it serves, and the highest migration the store has applied. A
|
|
// put-back of the controller to a build that reaches less than the store is refused (gate.go), because
|
|
// such a controller starts behind its own records and judges with what it can read.
|
|
|
|
// RecordSchemaReach keeps the highest migration the build serving now carries.
|
|
func (i *Inventory) RecordSchemaReach(ctx context.Context, build string, reach int) error {
|
|
if build == "" {
|
|
return errors.New("a schema reach is recorded by a build's version, and this controller has none")
|
|
}
|
|
_, err := i.store.Pool().Exec(ctx,
|
|
`insert into controller_schema (build, reach) values ($1, $2)
|
|
on conflict (build) do update set reach = excluded.reach, recorded = now()`, build, reach)
|
|
return err
|
|
}
|
|
|
|
// SchemaReachOf is the highest migration a build carries, as it recorded when it served; false for a
|
|
// build that never did.
|
|
func (i *Inventory) SchemaReachOf(ctx context.Context, build string) (int, bool, error) {
|
|
var reach int
|
|
err := i.store.Pool().QueryRow(ctx, `select reach from controller_schema where build = $1`, build).Scan(&reach)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return 0, false, nil
|
|
}
|
|
return reach, err == nil, err
|
|
}
|
|
|
|
// SchemaApplied is the highest migration the store has applied.
|
|
func (i *Inventory) SchemaApplied(ctx context.Context) (int, error) {
|
|
var n *int
|
|
if err := i.store.Pool().QueryRow(ctx, `select max(number) from migration`).Scan(&n); err != nil {
|
|
return 0, err
|
|
}
|
|
if n == nil {
|
|
return 0, nil
|
|
}
|
|
return *n, nil
|
|
}
|