Files
worker/docs/tasks-and-notifications.md
Gleb Tv e987f24903
Все проверки выполнены успешно
CI / test (push) Successful in 2m32s
Docker / Build and publish worker image (push) Successful in 18m17s
fix(worker): harden control-plane lifecycle
- 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.
2026-07-19 23:11:43 +03:00

136 строки
6.3 KiB
Markdown

# Normal Tasks And Notifications
## Normal Check Execution
Normal work is centrally scheduled. The control plane owns PostgreSQL task
rows, selection, leases, retries, deadlines, and dead-letter state. The worker
owns only one execution attempt and its terminal report.
The implemented path is:
1. `internal/distworker/client.go` opens the authenticated WebSocket.
2. `internal/distworker/runner.go` selects a recognized populated task branch.
3. A bounded worker pool executes the task under its deadline.
4. `internal/checkexec/exec.go` dispatches to a database-free check package.
5. The runner queues one result and the result writer returns it to the control
plane with the exact lease token.
Implemented check kinds are HTTP, SSL, SSH, FTP, DNS, WHOIS, BSSL, LLM,
LLM-HTTP, ping, TCP, and UDP. Control-plane selection uses capabilities. The
runner and local executor share one supported-kind registry. Websocket task
envelopes require exactly one payload branch, matching non-empty outer/inner
job IDs, and a lease token. Unsupported checks return one terminal failed
result without execution. A safely attributable malformed single branch
returns a protocol failure; ambiguous and mismatched envelopes fail closed.
## Queue And Shutdown Rules
- Input and output queues are bounded. Backpressure must not create unbounded
goroutines or memory use.
- Concurrency is supplied by the control plane but clamped by the local
maximum.
- A task panic is recovered at the task boundary and reported as a failed
attempt; it must not kill the runner.
- SIGTERM stops accepting new tasks and waits for active dispatchers before the
execution pool closes. A bounded final-result drain across websocket shutdown
is not implemented yet.
- WebSocket reconnect does not re-run an in-flight or completed task.
- HTTP polling remains compatibility-only and must not become a second normal
scheduler.
## Delegated Notifications
`internal/distworker/notification.go` executes one pre-rendered delivery
attempt. It does not render alert policy and does not own retry scheduling.
| Method | State | Credential source |
| --- | --- | --- |
| Email | Implemented | scoped SMTP list from init/config |
| Telegram | Implemented | scoped bot list from init/config |
| Webhook | Implemented | current shared signing configuration |
| Mattermost | Implemented | current shared defaults/task endpoint |
| SMS | Explicitly unsupported | no provider selected |
| Voice | Explicitly unsupported | no provider selected |
SMS and voice return `permanent` with `unsupported_method`; they must never be
reported as delivered or silently dropped.
Worker result statuses are `delivered`, `retryable`, `permanent`, and
`partial`. Transport failures, provider rate limits, and provider 5xx responses
are retryable. Invalid recipients, authentication failures, malformed payloads,
and unsupported methods are permanent. Positive provider retry-after values
are included in the result; the control plane owns the actual retry time.
## Credentials
Credentials arrive in `WorkerInit.Credentials` and remain in memory. SMTP and
Telegram tasks may request a credential ID; the worker resolves only that ID
from the authorized pushed set. Missing IDs are permanent failures. Do not
fall back to another account's or platform credential.
The following fields must be redacted from logs and UI buffers: password,
token, API key, signing secret, hook URL, authorization headers, and fields
ending in `_secret`. Provider response text is bounded and must not include
response bodies that could contain secrets.
Webhook and Mattermost need persisted per-account credentials in the control
plane before they can claim the same isolation guarantees as SMTP and
Telegram. The worker wire shape already separates method configuration; do not
introduce environment-global fallback for private workers.
## Selfcheck Notifications
System selfcheck alerts are not normal notification tasks. They allow a worker
to notify configured system contacts when the control plane itself is
unreachable. They use system contacts and credentials from config, local
jitter, and local deduplication. They must not impersonate customer delivery or
mutate control-plane message state.
The local notifications page records both selfcheck and delegated delivery
attempts. Delegated rows contain job ID, method, status, duration, and time
only. Recipient, body, credentials, hook URL, authorization, provider response,
and error text are never copied into the bounded ring. Invalid deadlines and
recovered executor panics produce static permanent results and one redacted
local row.
## Implementation Work Packages
### N1: Runner Integration Coverage (partial)
Strict envelope/inner job-ID/lease validation and structured unsupported-kind
results are implemented with runner-boundary tests. Live WebSocket reconnect
and result-resend tests are implemented. Stale-lease acknowledgement and
bounded graceful final-drain tests remain.
### N2: Complete Local Delivery Audit (implemented)
Delegated notification outcomes are recorded in the bounded local notification
ring. `/notifications` renders selfcheck and delegated attempts without storing
recipient values, rendered body, credentials, provider responses, or errors.
### N3: Per-Account Webhook And Mattermost Credentials
Once the control plane sends credential IDs and account-scoped records, require
an exact credential match just like SMTP and Telegram. Remove global fallback
for private workers. Add cross-account negative tests.
### N4: SMS And Voice Providers
Select a provider and define a credential wire type before adding an executor.
Implementation must include timeout, retry classification, provider response
redaction, idempotency support, and contract tests. Until all are present,
retain the explicit permanent unsupported result.
## Acceptance Tests
- Every supported check kind can execute from a serialized task without a
database connection.
- A stale or missing lease token cannot produce an accepted normal result.
- One task causes at most one local execution during reconnect and duplicate
frame delivery.
- Private workers cannot resolve a credential outside their authorized set.
- SMTP 4xx/rate-limit conditions are retryable; invalid authentication is
permanent.
- SMS and voice remain explicit failures until provider tests exist.
- Logs and local UI contain no pushed credential values.