188 lines
4.7 KiB
Markdown
188 lines
4.7 KiB
Markdown
# Runtime and Components
|
|
|
|
The diagram below focuses on the deployed `galaxy/mail` process and its runtime
|
|
dependencies.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
subgraph Callers
|
|
Auth["Auth / Session Service"]
|
|
Notify["Notification Service"]
|
|
Ops["Trusted operators"]
|
|
end
|
|
|
|
subgraph Mail["Mail Service process"]
|
|
InternalHTTP["Trusted internal HTTP listener\n/api/v1/internal/*"]
|
|
Consumer["Redis Stream command consumer"]
|
|
Scheduler["Attempt scheduler"]
|
|
Workers["Attempt worker pool"]
|
|
Cleanup["Index cleanup worker"]
|
|
Services["Application services"]
|
|
Templates["Immutable template catalog"]
|
|
Telemetry["Logs, traces, metrics"]
|
|
end
|
|
|
|
Redis["Redis\nstate + streams + indexes"]
|
|
Provider["SMTP or stub provider"]
|
|
|
|
Auth --> InternalHTTP
|
|
Ops --> InternalHTTP
|
|
Notify --> Redis
|
|
InternalHTTP --> Services
|
|
Consumer --> Services
|
|
Scheduler --> Services
|
|
Workers --> Services
|
|
Cleanup --> Services
|
|
Services --> Templates
|
|
Services --> Redis
|
|
Services --> Provider
|
|
InternalHTTP --> Telemetry
|
|
Consumer --> Telemetry
|
|
Scheduler --> Telemetry
|
|
Workers --> Telemetry
|
|
```
|
|
|
|
## Listener
|
|
|
|
`mail` exposes exactly one HTTP listener:
|
|
|
|
| Listener | Default addr | Purpose |
|
|
| --- | --- | --- |
|
|
| Internal HTTP | `:8080` | Trusted intake, operator reads, and resend |
|
|
|
|
Shared listener defaults:
|
|
|
|
- read-header timeout: `2s`
|
|
- read timeout: `10s`
|
|
- idle timeout: `1m`
|
|
|
|
Intentional omissions:
|
|
|
|
- no public listener
|
|
- no `/healthz`
|
|
- no `/readyz`
|
|
- no `/metrics`
|
|
|
|
## Startup Wiring
|
|
|
|
`cmd/mail` loads config, constructs logging, and builds the runtime through
|
|
`internal/app.NewRuntime`.
|
|
|
|
The runtime wires:
|
|
|
|
- Redis clients for state access and blocking stream consumption
|
|
- filesystem-backed template catalog
|
|
- provider adapter selected by `MAIL_SMTP_MODE`
|
|
- acceptance, render, execution, operator-read, and resend services
|
|
- internal HTTP server
|
|
- command consumer
|
|
- scheduler
|
|
- attempt worker pool
|
|
- cleanup worker
|
|
|
|
Before startup completes, the process performs bounded `PING` checks for both
|
|
Redis clients and validates the template catalog. Startup fails fast on invalid
|
|
configuration or unavailable Redis.
|
|
|
|
## Background Components
|
|
|
|
### Command consumer
|
|
|
|
- reads one plain `XREAD` stream
|
|
- starts from stored offset or `0-0`
|
|
- advances offset only after durable command acceptance or durable malformed
|
|
command recording
|
|
|
|
### Scheduler
|
|
|
|
- polls due work every `250ms`
|
|
- recovers stale claims every `30s`
|
|
- derives recovery deadline from `MAIL_SMTP_TIMEOUT + 30s`
|
|
|
|
### Attempt worker pool
|
|
|
|
- processes only already claimed work items
|
|
- concurrency is controlled by `MAIL_ATTEMPT_WORKER_CONCURRENCY`
|
|
|
|
### Cleanup worker
|
|
|
|
- removes stale delivery-index members after primary delivery expiry
|
|
- does not clean `mail:attempt_schedule`
|
|
- does not clean malformed-command index entries
|
|
|
|
## Configuration Groups
|
|
|
|
Required for all starts:
|
|
|
|
- `MAIL_REDIS_ADDR`
|
|
|
|
Core process config:
|
|
|
|
- `MAIL_SHUTDOWN_TIMEOUT`
|
|
- `MAIL_LOG_LEVEL`
|
|
|
|
Internal HTTP config:
|
|
|
|
- `MAIL_INTERNAL_HTTP_ADDR`
|
|
- `MAIL_INTERNAL_HTTP_READ_HEADER_TIMEOUT`
|
|
- `MAIL_INTERNAL_HTTP_READ_TIMEOUT`
|
|
- `MAIL_INTERNAL_HTTP_IDLE_TIMEOUT`
|
|
|
|
Redis connectivity:
|
|
|
|
- `MAIL_REDIS_USERNAME`
|
|
- `MAIL_REDIS_PASSWORD`
|
|
- `MAIL_REDIS_DB`
|
|
- `MAIL_REDIS_TLS_ENABLED`
|
|
- `MAIL_REDIS_OPERATION_TIMEOUT`
|
|
- `MAIL_REDIS_COMMAND_STREAM`
|
|
- `MAIL_REDIS_ATTEMPT_SCHEDULE_KEY`
|
|
- `MAIL_REDIS_DEAD_LETTER_PREFIX`
|
|
|
|
SMTP provider:
|
|
|
|
- `MAIL_SMTP_MODE`
|
|
- `MAIL_SMTP_ADDR`
|
|
- `MAIL_SMTP_USERNAME`
|
|
- `MAIL_SMTP_PASSWORD`
|
|
- `MAIL_SMTP_FROM_EMAIL`
|
|
- `MAIL_SMTP_FROM_NAME`
|
|
- `MAIL_SMTP_TIMEOUT`
|
|
- `MAIL_SMTP_INSECURE_SKIP_VERIFY`
|
|
|
|
Templates and workers:
|
|
|
|
- `MAIL_TEMPLATE_DIR`
|
|
- `MAIL_ATTEMPT_WORKER_CONCURRENCY`
|
|
- `MAIL_STREAM_BLOCK_TIMEOUT`
|
|
- `MAIL_OPERATOR_REQUEST_TIMEOUT`
|
|
- `MAIL_IDEMPOTENCY_TTL`
|
|
- `MAIL_DELIVERY_TTL`
|
|
- `MAIL_ATTEMPT_TTL`
|
|
|
|
Telemetry:
|
|
|
|
- `OTEL_SERVICE_NAME`
|
|
- `OTEL_TRACES_EXPORTER`
|
|
- `OTEL_METRICS_EXPORTER`
|
|
- `OTEL_EXPORTER_OTLP_PROTOCOL`
|
|
- `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL`
|
|
- `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL`
|
|
- `MAIL_OTEL_STDOUT_TRACES_ENABLED`
|
|
- `MAIL_OTEL_STDOUT_METRICS_ENABLED`
|
|
|
|
## Runtime Notes
|
|
|
|
- `MAIL_REDIS_COMMAND_STREAM` is the only Redis key override that currently
|
|
changes runtime behavior
|
|
- `MAIL_SMTP_INSECURE_SKIP_VERIFY` is a local-development escape hatch for
|
|
self-signed SMTP capture only and should remain disabled in production
|
|
- attempt-schedule and dead-letter key overrides are parsed but not yet wired
|
|
into Redis adapters
|
|
- retention overrides are parsed but storage still uses the fixed `7d`, `30d`,
|
|
and `90d` values
|
|
- template catalog parsing is eager and immutable
|
|
- auth deliveries in `MAIL_SMTP_MODE=stub` surface as `suppressed`
|
|
- auth deliveries in `MAIL_SMTP_MODE=smtp` surface as `queued` and later move
|
|
through normal attempt execution
|