Integrate in Go
Minimal shape
svc := triggers.NewService("flow_lab")
svc.Ingress(triggers.NATS)
triggers.Action(svc, "parse", parse)
triggers.Action(svc, "wrap", wrap)
return svc.Run(ctx)
That is enough for a service with one ingress and a couple of actions.
Production-shaped service
func buildService(deps handlers.Deps) *triggers.Service {
svc := triggers.NewService("notify")
svc.Ingress(
triggers.NATS,
triggers.Kafka,
triggers.HTTP,
)
svc.EnableDedup()
svc.DataSource(
"templates",
handlers.TemplatesDataSource(deps),
triggers.DataSourceOpts{Description: "Notification templates for the selected tenant"},
)
handlers.RegisterAll(svc, deps)
return svc
}
HTTP ingress ownership
triggers.HTTP uses the canonical /v2/<service>/inbound path automatically.
When you need a different path, use triggers.HTTP.At("/custom/path") or triggers.HTTP.At("https://...").
For both forms, the SDK publishes the absolute HTTP endpoint by using:
TRIGGERS_HTTP_PUBLIC_BASE_URLwhen it is set- otherwise
TRIGGERS_HTTP_ADDR(default:8081)
Real services in this repo now use bare triggers.HTTP unless they truly need a custom route.
For simple local runs, TRIGGERS_HTTP_ADDR is usually enough on its own. Add TRIGGERS_HTTP_PUBLIC_BASE_URL only when the advertised URL should differ from the bind-address fallback.
Typical env
TRIGGERS_NATS_URL=nats://127.0.0.1:4222
TRIGGERS_KAFKA_BROKERS=127.0.0.1:9092
TRIGGERS_REDIS_URL=redis://127.0.0.1:6379/0
TRIGGERS_HTTP_ADDR=:8081
TRIGGERS_SERVICE_VERSION=local-dev
Wiring env map
| Var | Used for | When to set it |
|---|---|---|
TRIGGERS_NATS_URL | NATS registration, heartbeats, broadcasts, and NATS ingress | Required when the service runs in the real fleet |
TRIGGERS_NATS_CREDS_PATH | Optional NATS auth file | Only when the NATS cluster requires creds |
TRIGGERS_KAFKA_BROKERS | Kafka ingress wiring and canonical-topic ensure | Only when code declares triggers.Kafka |
TRIGGERS_KAFKA_INGRESS_TOPIC_PARTITIONS | Canonical Kafka ingress topic partitions | Optional override; default 1 |
TRIGGERS_KAFKA_INGRESS_TOPIC_REPLICATION_FACTOR | Canonical Kafka ingress topic replication factor | Optional override; default 1 |
TRIGGERS_KAFKA_INGRESS_TOPIC_RETENTION_MS | Canonical Kafka ingress topic retention in ms | Optional override; default 604800000 |
TRIGGERS_HTTP_ADDR | HTTP bind address and fallback advertised base | Usually set for HTTP ingress; local default is :8081 |
TRIGGERS_HTTP_PUBLIC_BASE_URL | Public HTTP base used in the manifest | Only when the advertised URL should differ from TRIGGERS_HTTP_ADDR |
TRIGGERS_SERVICE_VERSION | Manifest/runtime version string | Recommended in CI and shared environments |
TRIGGERS_REDIS_URL | Final Redis URL | Fastest local-dev option and highest-precedence runtime input |
TRIGGERS_REDIS_URL_SECRET_NAME | Key Vault secret name containing the full Redis URL | Use when platform stores the full URL as one secret |
TRIGGERS_REDIS_HOST | Literal host[:port] or redis[s]://... base | Use when the platform exposes host separately |
TRIGGERS_REDIS_HOST_SECRET_NAME | Key Vault secret name for host/base | Recommended repo pattern in Kubernetes when host is secret-backed |
TRIGGERS_REDIS_PASSWORD | Literal Redis password | Use only with host-based composition |
TRIGGERS_REDIS_PASSWORD_SECRET_NAME | Key Vault secret name for Redis password | Recommended repo pattern in Kubernetes when password is secret-backed |
TRIGGERS_REDIS_DB | Redis DB suffix when composing a URL from host/password inputs | Set it only when the chosen Redis host does not already include a DB path |
KEY_VAULT_URL | Azure Key Vault base URL for any *_SECRET_NAME lookup | Required whenever any Redis secret-name var is set |
If the service enables EnableDedup() or EnableRateLimit(), Kubernetes can provide Redis through TRIGGERS_REDIS_URL, TRIGGERS_REDIS_URL_SECRET_NAME, or host/password inputs plus optional TRIGGERS_REDIS_DB. The SDK resolves that contract lazily, TRIGGERS_REDIS_URL still wins by precedence, and any Redis *_SECRET_NAME input requires KEY_VAULT_URL.
In this repo, the usual Kubernetes pattern is:
envFromSecrets:
- azure-app
environment:
TRIGGERS_REDIS_HOST_SECRET_NAME: "<env-specific-redis-host-secret>"
TRIGGERS_REDIS_PASSWORD_SECRET_NAME: "<env-specific-redis-password-secret>"
TRIGGERS_REDIS_DB: "<service-specific-db>"
azure-app typically injects the Azure credential env plus KEY_VAULT_URL, so the SDK can resolve the Redis secret-name inputs without service-specific bootstrap code.
For Kafka ingress, keep the declaration canonical and code-owned: triggers.Kafka always advertises triggers_v2_<service>_inbound. Released flows may point Kafka delivery at another topic, but that retarget belongs only in released flow config. The SDK ensures only the canonical topic before it starts the consumer. If it has to create that topic, it uses explicit retention.ms plus cleanup.policy=delete, with defaults of 1 partition, replication factor 1, and 604800000 ms retention unless you override them with the TRIGGERS_KAFKA_INGRESS_TOPIC_* env vars. Invalid TRIGGERS_KAFKA_INGRESS_TOPIC_* values fail fast during config parsing. Non-canonical flow targets must already exist; the SDK only probes them for existence and will not create them. If a retargeted topic is missing, reconcile fails closed: the runtime closes the stale Kafka consumer instead of silently staying on the old topic, so the service can remain up while Kafka ingestion is unavailable until the topic exists or the flow is corrected.
Current repo examples
These are examples from the current repo, not universal defaults for every new service:
| Service | Environment | Suggested Redis wiring |
|---|---|---|
notify-sender | spark-dev1 | TRIGGERS_REDIS_HOST_SECRET_NAME=spark-dev-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-dev-redis-password, TRIGGERS_REDIS_DB=3 |
notify-sender | spark-prod-mexico1 | TRIGGERS_REDIS_HOST_SECRET_NAME=spark-mexico1-prod-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-mexico1-prod-redis-password, TRIGGERS_REDIS_DB=3 |
spark_bonus | spark-dev1 | TRIGGERS_REDIS_HOST_SECRET_NAME=spark-dev-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-dev-redis-password, TRIGGERS_REDIS_DB=5 |
spark_bonus | spark-prod-mexico1 | TRIGGERS_REDIS_HOST_SECRET_NAME=spark-mexico1-prod-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-mexico1-prod-redis-password, TRIGGERS_REDIS_DB=5 |
Do not reuse a DB index just because another service already uses it. Keep the existing service-specific DB assignment unless operations explicitly approve a different one.
Local verification
- Run the service.
- Check
curl -s http://localhost:8888/api/v2/services/<service> | jq .manifest. - Confirm
service_sourcesandtransportsmatch the declared ingress. - Release one flow and exercise each ingress you intend to support.