8.3 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
Development mode defaults to
nats.mode = "core", so the processor consumes directly from the configured subject (subscription.topic). However, the publisher always targets JetStream for deduplicated fan-out, so the provided Taskfile (and most examples below) override the mode tojetstream. If you truly need core mode, setCAATSM_NATS_MODE=coremanually and ensure any publishers use core subjects.
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 (includingCAATSM_NATS_MODE=jetstream), 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):
# Insert rows into aviation.telegrams_raw and publish to NATS simultaneously
GO_ENV=dev go run ./cmd/seed-telegrams \
--postgres-url postgres://caatsm:caatsm@localhost:5432/aviation?sslmode=disable \
--nats-url nats://127.0.0.1:4222 \
--subject telegram.serial \
--count 20 \
--category mixed \
--status random
--postgres-urlcontrols database insertion (omit to skip DB writes); metadata lands inaviation.telegrams_raw.metadata.--dry-runprints telegrams without touching NATS/Postgres.--categorychooses ARR/DEP/CNL/DLA/FPL ormixed.--statuscontrols stored/published status (parsed|header_error|body_error|publish_error|repository_error|random).--no-natsdisables publishing;--jetstream,--stream,--js-subjecttoggle JetStream publishing.- Inspect deliveries with
docker compose exec nats-box nats sub 'telegram.>'. - When running in core mode (default), the seeder publishes via standard
nc.Publishand setsNats-Msg-Idheaders so the processor can derive message IDs.
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
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.