Documentation
¶
Overview ¶
Package executor orchestrates one backup attempt end-to-end.
An Executor is called by pkg/controlplane/runtime/storebackups.Service from both cron-driven schedule ticks and Phase 6's on-demand POST /backups handler (D-23). It is store-agnostic: takes a Backupable source, a Destination, a BackupRepo row, and a narrow JobStore interface covering only the three persistence calls it needs.
Sequence (D-21):
- ulid.Make() → recordID
- CreateBackupJob(status=running, started_at=now)
- Build manifest.Manifest{BackupID=recordID, StoreID, Encryption, ...}
- io.Pipe: source.Backup(ctx, w) || dst.PutBackup(ctx, &m, r)
- On success: CreateBackupRecord(id=recordID, sha256=m.SHA256, size=m.SizeBytes, status=succeeded) UpdateBackupJob(status=succeeded, finished_at=now, backup_record_id=&recordID)
- On failure: UpdateBackupJob(status=failed|interrupted, error=err.Error()) — no BackupRecord is created (D-16)
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor runs one backup attempt per RunBackup call.
func (*Executor) RunBackup ¶
func (e *Executor) RunBackup( ctx context.Context, source backup.Backupable, dst destination.Destination, repo *models.BackupRepo, storeID string, storeKind string, opts ...RunBackupOption, ) (*models.BackupRecord, *models.BackupJob, error)
RunBackup executes one backup attempt. Returns (rec, job, nil) on success where rec is the persisted BackupRecord and job is the synchronously persisted BackupJob row; (nil, job-or-nil, err) on failure — job is non-nil after the synchronous CreateBackupJob has succeeded (so Phase 6 callers can still surface the job ID to clients for polling). Pre-CreateBackupJob failures (nil-arg guards, createJobErr) return (nil, nil, err).
storeID is the source metadata store ID snapshotted into manifest.StoreID AND BackupRecord.StoreID (cross-store restore guard per Phase 1). storeKind is "memory" | "badger" | "postgres" (written to manifest.StoreKind).
Failure semantics (D-16, D-18):
- source or destination returns non-nil error → BackupJob transitions to failed (or interrupted on ctx cancel / backup.ErrBackupAborted); NO BackupRecord row is created.
- ctx cancellation → BackupJob ends with Status=interrupted.
- CreateBackupRecord fails after PutBackup succeeded → BackupJob marked failed with an explicit "archive published but record persist failed" message; operator can reconcile via orphan sweep.
type JobStore ¶
type JobStore interface {
CreateBackupJob(ctx context.Context, job *models.BackupJob) (string, error)
UpdateBackupJob(ctx context.Context, job *models.BackupJob) error
UpdateBackupJobProgress(ctx context.Context, jobID string, pct int) error
CreateBackupRecord(ctx context.Context, rec *models.BackupRecord) (string, error)
}
JobStore is the narrow persistence interface the Executor needs. A subset of store.BackupStore — callers pass the full store but the Executor only consumes these four methods, which keeps test fakes trivial.
UpdateBackupJobProgress is the Phase 6 D-50 stage-marker hook. Callers log WARN on failure and do NOT fail the parent op (best-effort semantics).
type RunBackupOption ¶
type RunBackupOption func(*runBackupConfig)
RunBackupOption tunes a single RunBackup invocation. Options are per-call so concurrent RunBackup calls (different repos) do not race on shared executor state.
func WithOnJobCreated ¶
func WithOnJobCreated(fn func(*models.BackupJob)) RunBackupOption
WithOnJobCreated installs a callback invoked synchronously inside RunBackup immediately after CreateBackupJob succeeds (i.e. the BackupJob row is persisted with Status=running) and BEFORE the destination PutBackup begins. Phase 6 (D-43) uses this hook to register the run-ctx's cancel func against job.ID so CancelBackupJob can interrupt the in-flight run.
The callback must not block for long — it executes on the RunBackup goroutine and delays the payload stream.