9.7 KiB
Development Guide
This document describes how to run the full development stack—database, NATS, and observability tooling—using docker-compose.dev.yml. All commands assume you are at the repository root.
Core Services (TimescaleDB + NATS)
Spin up PostgreSQL/TimescaleDB and NATS JetStream in the background:
docker compose -f docker-compose.dev.yml up -d postgres nats nats-box
NATS Mode Selection: The application supports two consumption modes:
- Core NATS mode (default for development): Simple pub/sub without persistence or retry mechanisms. Recommended for local development and testing where message loss is acceptable. Fast and lightweight.
- JetStream mode: Provides message persistence, ACK/NAK, automatic retries, and DLQ support. Recommended for production environments and integration testing.
Development mode defaults to
nats.mode = "core"inconfig.dev.toml. To use JetStream in development, setCAATSM_NATS_MODE=jetstreamor change the config file. Note: The publisher always targets JetStream for deduplicated fan-out, so if you use Core mode for consumption, ensure your publishers align with your messaging strategy. See the README.md "NATS Mode Selection" section for a detailed comparison.
postgresseeds theaviationschema usinginternal/infra/postgres/telegrams.ddland exposes port5432.natsenables JetStream with client port4222and monitoring/UI on8222.nats-boxprovides a toolbox container (docker compose exec nats-box sh) for publishing test messages or inspecting JetStream.nats-exporterscrapes the monitoring endpoints (/varz,/connz,/routez,/subz) and exposes them as Prometheus metrics on port7777for the Grafana dashboards.
Prefer to run the Go application on your host for quick iteration while keeping infra in Docker:
GO_ENV=dev \
CAATSM_POSTGRES_URL=postgres://caatsm:caatsm@localhost:5432/aviation?sslmode=disable \
go run ./cmd/main listen
Stop and clean the stack when finished:
docker compose -f docker-compose.dev.yml down -v
In development (GO_ENV=dev or unset), if you run the application while
stopping and recreating the NATS/JetStream containers (for example:
docker compose -f docker-compose.dev.yml down -v
docker compose -f docker-compose.dev.yml up -d postgres nats nats-box
), the JetStream state will be reset. The processor behaves as follows:
- The NATS client keeps retrying the connection and automatically reconnects when NATS is back.
- The JetStream consumer detects missing streams/consumers and, in dev/test
environments, uses shared
EnsureStream/ensureConsumerlogic to auto-recreate them. - In production environments, missing streams/consumers are treated as configuration/operational errors and are not auto-recreated; operators should investigate and fix the underlying issue.
Using Taskfile shortcuts
The Taskfile.yml includes helper targets that wrap the commands above:
task up– starts PostgreSQL, NATS (JetStream, toolbox, and Prometheus exporter), and the observability stack (OpenTelemetry Collector, Jaeger, Prometheus, Grafana) using Docker Compose.task dev-run– ensurestask uphas run, exports the necessaryCAATSM_*environment variables (defaults toCAATSM_NATS_MODE=corefor development), and executesgo run ./cmd/main listenwith telemetry enabled.task down– stops the entire stack and removes containers/volumes.
Use these tasks if you prefer a one-command workflow instead of invoking docker compose and environment exports manually.
Publishing Sample Telegrams
Use the helper CLI in cmd/seed-telegrams to push realistic payloads onto NATS (mirrors the fixtures in internal/adapter/parser/aviation_parser_test.go):
Publishing to JetStream (Recommended)
When using JetStream mode, publish messages to the JetStream stream:
# Publish to JetStream stream (messages are persisted)
GO_ENV=dev go run ./cmd/seed-telegrams \
--nats-url nats://127.0.0.1:4222 \
--jetstream \
--stream TELEGRAM \
--js-subject telegram.serial \
--count 20 \
--category mixed \
--status random
Publishing to Core NATS
For Core NATS mode, use standard publish:
# Publish to Core NATS (no persistence)
GO_ENV=dev go run ./cmd/seed-telegrams \
--nats-url nats://127.0.0.1:4222 \
--subject telegram.serial \
--count 20 \
--category mixed \
--status random
Common Options
--postgres-url: Insert rows intoaviation.telegrams_raw(omit to skip DB writes)--dry-run: Print telegrams without publishing to NATS/Postgres--category: Choose message type (ARR|DEP|CNL|DLA|FPL|mixed)--status: Control stored/published status (parsed|header_error|body_error|publish_error|repository_error|random)--no-nats: Disable publishing to NATS--jetstream: Enable JetStream publishing (requires--streamand--js-subject)--stream: JetStream stream name (default:TELEGRAM)--js-subject: Subject within the JetStream stream
Inspecting Messages
# View messages in JetStream stream
docker compose exec nats-box nats stream view TELEGRAM
# Subscribe to messages (Core NATS or JetStream)
docker compose exec nats-box nats sub 'telegram.>'
# View consumer status and pending messages
docker compose exec nats-box nats consumer info TELEGRAM telegram-consumer
The main processor keeps consuming subscription.topic (defaults to telegram.>). Use the seeder to simulate parser failures, publish errors, or replay raw telegrams directly from the database.
Tracing with Jaeger
-
Start the observability stack
docker compose -f docker-compose.dev.yml up -d otel-collector jaeger prometheus grafana- Jaeger UI runs at http://localhost:16686.
- The OTLP HTTP collector endpoint is available at
http://localhost:4318.
-
Run the processor with telemetry enabled
# Using Core NATS mode (default for development) CAATSM_TELEMETRY_ENABLED=true \ CAATSM_TELEMETRY_ENDPOINT=localhost:4318 \ CAATSM_TELEMETRY_INSECURE=true \ GO_ENV=dev \ CAATSM_POSTGRES_URL=postgres://caatsm:caatsm@localhost:5432/aviation?sslmode=disable \ go run ./cmd/main listen # Or use JetStream mode for integration testing CAATSM_TELEMETRY_ENABLED=true \ CAATSM_TELEMETRY_ENDPOINT=localhost:4318 \ CAATSM_TELEMETRY_INSECURE=true \ GO_ENV=dev \ CAATSM_NATS_MODE=jetstream \ CAATSM_POSTGRES_URL=postgres://caatsm:caatsm@localhost:5432/aviation?sslmode=disable \ go run ./cmd/main listen- The service name reported to Jaeger is
caatsm.
- The service name reported to Jaeger is
-
Generate traffic
task seed COUNT=5or publish manually with
go run ./cmd/seed-telegrams. -
Inspect traces
- Open http://localhost:16686, choose the
caatsmservice, and click “Find Traces”. - Filter by operation name (e.g.,
Consumer.processMessage) or by time range to drill into individual telegram processing flows.
- Open http://localhost:16686, choose the
Observability Dashboard Stack
The dev compose file also includes OpenTelemetry Collector, Jaeger, Prometheus, and Grafana so you can inspect traces and metrics emitted by the processor.
docker compose -f docker-compose.dev.yml up -d \
postgres nats otel-collector jaeger prometheus grafana
Services:
otel-collector- Loads
configs/otel-collector.dev.yaml - Ports: OTLP gRPC
4317, OTLP HTTP4318, Prometheus scrape8888, Prometheus exporter8889, health13133, zPages55679 - Exports traces to Jaeger via the built-in OTLP gRPC exporter (secured with
tls.insecure: true)
- Loads
jaeger- Receives OTLP traffic forwarded from the collector on
14250gRPC and serves the UI at http://localhost:16686
- Receives OTLP traffic forwarded from the collector on
prometheus- Uses
configs/prometheus.dev.ymlto scrape the collector,nats-exporter(http://nats-exporter:7777/metrics), and application OTLP metrics forwarded via the collector; UI available at http://localhost:9090
- Uses
grafana- Persists data in
grafana-data, provisions datasources viaconfigs/grafana-datasources.dev.yml, and listens on http://localhost:3000 (loginadmin/admin) - Automatically loads dashboards from
configs/grafana-dashboards.dev/, including OpenTelemetry Collector and NATS/JetStream overviews (find them under the Dev Observability folder) - The OpenTelemetry dashboard also charts the CAATSM-specific metrics
caatsm_messages_processed_total,caatsm_publish_failures_total, andcaatsm_parse_duration_ms(percentiles) so you can track throughput and parsing latency. - Note:
caatsm_parse_duration_mshas been renamed tocaatsm_parse_duration_secondsto align with Prometheus_secondsconventions.
- Persists data in
Customizing Collections & Dashboards
- Adjust
configs/prometheus.dev.ymlto add/remove scrape jobs—for example, include your application’s/metricsendpoint. - Add more Grafana provisioning files (dashboards, alert rules) under
configs/and mount them indocker-compose.dev.yml. - To ingest telemetry from local services, configure their OTLP exporters to target
http://localhost:4318(HTTP) orgrpc://localhost:4317.
Troubleshooting
- PostgreSQL init errors: ensure
internal/infra/postgres/telegrams.ddlis valid SQL and thepostgres-datavolume is removed (docker volume rm go-caatsm_postgres-data) before restarting. - NATS connection failures: confirm ports
4222/8222are free and JetStream is enabled; usedocker compose logs nats. - Prometheus scrape failures: verify endpoints listed in
configs/prometheus.dev.ymlmatch the service names defined in Docker Compose. - Grafana provisioning issues: check container logs (
docker compose logs grafana) to ensure the datasources file was read; correct file permissions or YAML formatting if provisioning is skipped.