agentpush

package
v0.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

  • secretsreconcile — the level-triggered reconcile loop.
  • ForceRevokeSecret fan-out — revocation is absence (I12).

Notify never carries secret material: it only shrinks latency. If a notify fails, the reconcile loop converges the workspace on a later pass (I3: notify failure costs latency, never correctness).

M2 (validation): a 429 that carries retryAfterMs schedules ONE deferred retry (capped 2.5s) so a rapid second mutation does not lose its notify until the next 60s loop pass. The retry runs detached from any request context, never blocks the bind path, is canceled by Stop, and never schedules a second retry — if the retry also 429s, the reconcile loop owns convergence.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoPodIPResolver — the service was constructed without a resolver.
	// A wiring bug; the service can't deliver anything and should not have
	// been used. Return 503 at the HTTP boundary.
	ErrNoPodIPResolver = errors.New("agentpush: pod IP resolver not configured")
	// ErrNoRunningPod — the workspace exists but has no reachable pod
	// right now (Pending, Suspended, or recreating). Not a hard failure:
	// user-initiated callers surface 409, background callers log at info
	// and record the "no_pod" metric outcome (transient during pod boot
	// races).
	ErrNoRunningPod = errors.New("agentpush: workspace has no running pod")
	// ErrNoPasswordProvider — the service was constructed without a
	// password provider. A wiring bug; agentd enforces Basic auth on the
	// user mux (#848) so the dispatch cannot succeed.
	ErrNoPasswordProvider = errors.New("agentpush: password provider not configured")
)

Sentinels — callers switch on these to map to HTTP status codes.

Functions

This section is empty.

Types

type ModelCache

type ModelCache interface {
	Evict(workspaceID string)
}

ModelCache is invalidated after a notify the pod acted on (applied) so ListModels refetches against the fresh provider set. Optional; nil skips the eviction.

type NotifyResult added in v0.27.0

type NotifyResult struct {
	Status     string `json:"status"`
	AppliedRev string `json:"appliedRev"`
	Restarted  bool   `json:"restarted"`
}

NotifyResult reports what agentd did with the resync request.

type Option

type Option func(*Service)

Option configures a Service.

func WithHTTPClient

func WithHTTPClient(c *http.Client) Option

WithHTTPClient overrides the default 5s-timeout HTTP client (tests).

func WithLogger

func WithLogger(l pkginterfaces.LoggerInterface) Option

WithLogger installs the logger used for non-fatal warnings.

func WithModelCache

func WithModelCache(c ModelCache) Option

WithModelCache installs the cache to evict after the pod applied a resync.

func WithNotifyMetricsHook added in v0.27.0

func WithNotifyMetricsHook(hook func(outcome string)) Option

WithNotifyMetricsHook installs an outcome-recording callback for notify dispatches. Outcomes: "success", "rate_limited", "retry_scheduled" (a 429's deferred retry was armed; it records its own outcome when it fires), "no_pod", "failed". Optional; nil is silently skipped.

func WithPasswordProvider added in v0.15.9

func WithPasswordProvider(p PasswordProvider) Option

WithPasswordProvider installs the workspace-password lookup required for the authenticated dispatch (#848).

func WithPodIPResolver

func WithPodIPResolver(r PodIPResolver) Option

WithPodIPResolver installs the pod-IP lookup.

type PasswordProvider added in v0.15.9

type PasswordProvider interface {
	WorkspacePassword(ctx context.Context, workspaceID string) (string, error)
}

PasswordProvider resolves the workspace's agentd Basic-auth password. agentd rejects unauthenticated posts on its user mux (#848); satisfied by interfaces.WorkspacePasswordProvider (US-46.11).

type PodIPResolver

type PodIPResolver interface {
	GetWorkspacePodIP(ctx context.Context, userID, workspaceID string) (string, error)
}

PodIPResolver looks up the running pod IP for a workspace. Returns an empty string (and nil error, or a wrapped one) when no pod is running.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the concrete notifier.

func New

func New(opts ...Option) *Service

New builds a Service from options alone: a notify carries no payload, so there is no builder dependency. podResolver/passwords may be nil during early wiring, in which case Notify returns the corresponding sentinel.

func (*Service) Notify added in v0.27.0

func (s *Service) Notify(ctx context.Context, userID, workspaceID string) (NotifyResult, error)

Notify asks the workspace pod's agentd to re-pull its secret batch via POST /v1/resync-secrets: an empty body, the workspace-password Basic credential, and nothing else. The pod performs the v2 conditional bootstrap pull in-process and reports what it applied.

Outcome contract:

  • 200 (applied | not_modified) → nil error, NotifyResult decoded.
  • 429 rate_limited → nil error: the pod is rate-limiting pulls. When the 429 carries retryAfterMs, ONE deferred retry is armed (min(retryAfterMs, 2.5s); M2) and the dispatch counts as "retry_scheduled"; without retryAfterMs (or after Stop) it stays "rate_limited" — the pod resyncs under its own budget either way.
  • 502 failed (pull_failed | pull_unauthorized) and every transport failure → error. Callers treat these as latency loss only; the reconcile loop retries with backoff (I3).

func (*Service) PushDevPreviewState added in v0.34.17

func (s *Service) PushDevPreviewState(ctx context.Context, userID, workspaceID string, enabled bool) error

PushDevPreviewState delivers the workspace's absolute dev-preview state to the running pod's agentd (POST /v1/dev-preview-state) so feature_status / dev_preview_url report the live toggle instead of the boot-time env snapshot (#1617). Fire-and-forget by design: the CRD remains the source of truth, a failed push costs only in-pod report latency, and the next pod build re-projects the env correctly.

func (*Service) PushUserTimezone added in v0.31.0

func (s *Service) PushUserTimezone(ctx context.Context, userID, workspaceID, timezone string) error

PushUserTimezone delivers the user's browser-reported IANA zone to a workspace pod's agentd (POST /v1/user-timezone) so get_datetime can render user-local time. Fire-and-forget by design: failures are latency-only — the next browser (re)connect re-pushes, and the pod keeps its last-known zone meanwhile.

func (*Service) Stop added in v0.27.0

func (s *Service) Stop()

Stop cancels pending deferred retries and waits for one already in flight (bounded by the HTTP client timeout). Idempotent; the service stays usable for direct (non-deferred) notifies afterwards.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL