Files
DDI/agent/core/source.go
T
beug.k@beugsiud.deandClaude Opus 5.5 9a4046e3e2 feat(agent): push deployments by polling, apply each deployment once
- GetDesiredStateResponse.deployment_id set: the desired revision is
  applied as a push with that ID, also in manual mode (ADR 0022).
- The reports of the last 20 push deployments are kept in state.json.
  A resent push with a handled deployment ID is not applied again; its
  report is delivered again unless it is still queued.
- A push already queued with the same deployment ID is not queued twice.
- Reports the server refuses for good (InvalidArgument, NotFound,
  AlreadyExists, FailedPrecondition, OutOfRange) are dropped instead of
  blocking the report queue.
- Tests for polling pushes, resent pushes, mode changes via a new
  Welcome, persistence and bounds of handled deployments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:07:35 +02:00

83 lines
2.9 KiB
Go

// SPDX-License-Identifier: Apache-2.0
package core
import (
"context"
"errors"
"time"
)
// ErrReportRefused marks a deployment report that the source refused for
// good (invalid, or for a deployment it no longer expects). Retrying it
// would block the reports queued behind it.
var ErrReportRefused = errors.New("deployment report refused")
// Source is where the agent learns its desired revision, fetches bundles and
// reports results (docs/adr/0010-agent-binaries-pro-rolle.md). M3 provides
// ServerSource (gRPC); a FileSource for standalone operation (M7) implements
// the same interface without changes to the apply pipeline.
type Source interface {
// Run delivers events to h until ctx is canceled. It returns ctx.Err()
// on shutdown or an error if the source cannot work at all.
Run(ctx context.Context, h SourceHandler) error
// FetchBundle returns the signed bundle of a revision. The caller
// verifies it.
FetchBundle(ctx context.Context, revision uint64) (*Bundle, error)
// ReportDeployment delivers an apply outcome. An error wrapping
// ErrReportRefused means that the report will never be accepted; the
// agent then drops it instead of retrying.
ReportDeployment(ctx context.Context, r DeploymentReport) error
// ReportLeases delivers a batch of lease observations.
ReportLeases(ctx context.Context, b LeaseBatch) error
}
// SourceHandler receives the events of a Source. Its methods must not
// block for long.
type SourceHandler interface {
// Connected is called whenever the source (re)established contact;
// the agent then sends queued reports and a full lease snapshot.
Connected()
// Desired announces the revision the agent should run. autoApply is
// false in manual mode, where only explicit pushes are applied.
Desired(revision uint64, autoApply bool)
// Push asks for an explicit apply of a revision. Unlike Desired, it
// also retries a revision that failed before. A push whose deployment
// ID was handled before is not applied again; its report is delivered
// (again) instead.
Push(revision uint64, deploymentID string)
// Status returns what the agent reports in Hello and heartbeats.
Status(ctx context.Context) AgentStatus
}
// AgentStatus is the agent's view of itself.
type AgentStatus struct {
Applied uint64
LastGood uint64
Health Health
CheckedAt time.Time
ServiceVersion string
}
// Bundle is a signed bundle as delivered by a Source.
type Bundle struct {
Manifest []byte
Signature []byte
Artifacts []BundleArtifact
}
// BundleArtifact is one artifact of a Bundle.
type BundleArtifact struct {
Path string
Content []byte
}
// LeaseBatch is one lease report. Sequence is monotonic per agent. A batch
// with FullSync replaces the server's view of all leases of this agent; the
// following batches (higher sequence) are changes on top of it.
type LeaseBatch struct {
Sequence uint64
FullSync bool
Leases []Lease
}