fix(worker): harden control-plane lifecycle
Все проверки выполнены успешно
CI / test (push) Successful in 2m32s
Docker / Build and publish worker image (push) Successful in 18m17s

- reconnect safely after token rotation and retry leased results
- reject malformed tasks and remove production cluster debug mutation
- validate environment files and require immutable container images

BREAKING CHANGE: Docker install, deploy, and Compose now require an
immutable repository@sha256 image reference.
Этот коммит содержится в:
Gleb Tv
2026-07-19 23:11:43 +03:00
родитель 6937674449
Коммит e987f24903
38 изменённых файлов: 2203 добавлений и 674 удалений

Просмотреть файл

@@ -80,16 +80,6 @@ type Config struct {
BasicAuthLogin string
BasicAuthPassword string
// DebugClusterApply gates the /web/api/cluster/apply-test-config
// endpoint. When false (the default) the route is registered but
// the handler returns 404 so the endpoint is invisible in
// production. Operators who want to poke the cluster FSM during
// development set WORKER_CLUSTER_DEBUG_APPLY=true. The endpoint
// must NEVER be reachable in production — it appends hardcoded
// log entries to the Raft FSM without going through the real
// config-adoption producer.
DebugClusterApply bool
// ReleaseURL is the optional URL the worker polls to discover
// the latest published version of the worker binary. When empty
// the /updates page shows the placeholder "v1 (dev)". The URL
@@ -186,7 +176,6 @@ func ConfigFromEnv(env map[string]string, defaultDataDir string) (Config, error)
if v := env["RSMON_WEBAPP_STORE_PATH"]; v != "" {
cfg.StorePath = v
}
cfg.DebugClusterApply = parseBool(env[envClusterDebugApply])
cfg.ReleaseURL = strings.TrimSpace(env[envReleaseURL])
return cfg, nil
}
@@ -212,7 +201,7 @@ func ConfigFromEnvOrDefault() Config {
envWorkerHost, envWorkerPort, envWorkerURL, envWorkerLogin, envWorkerPassword,
"RSMON_WEBAPP_DATA_DIR", "RSMON_WEBAPP_STORE_PATH",
"WORKER_CLUSTER_ENABLED",
envClusterDebugApply, envReleaseURL,
envReleaseURL,
} {
if v := os.Getenv(k); v != "" {
env[k] = v
@@ -254,7 +243,6 @@ type Deps struct {
// pulling in the raft package or bbolt.
type ClusterView interface {
Stats() ClusterStats
ApplyTestConfig() (uint64, error)
ClusterID() string
LocalAddr() string
}
@@ -320,9 +308,7 @@ type ResultRow struct {
At time.Time
}
// NotificationRow is one row from the worker's in-memory notification
// ring buffer. Phase 1 only emits selfcheck alerts; main-app-issued
// notifications still live in the main app's DB.
// NotificationRow is one row from the worker's in-memory notification ring.
type NotificationRow struct {
Kind string // "email", "telegram_private", "telegram_group"
Channel string
@@ -331,6 +317,11 @@ type NotificationRow struct {
OK bool
Error string
At time.Time
JobID string
Method string
Status string
DurationMs int
}
// Server is the local HTTP server for the worker webapp. It owns the