Skip to main content

Integrate in Python

Minimal shape

import asyncio

from triggers import NATS, Service

svc = Service("flow_lab")
svc.ingress(NATS)

@svc.action("parse")
async def parse(ctx, payload: ParseInput) -> ParseResult:
return ParseResult(message=payload.message, length=len(payload.message))

asyncio.run(svc.run())

Full-surface example

import asyncio

from triggers import HTTP, KAFKA, NATS, Service

svc = Service("notify")
svc.ingress(
NATS,
KAFKA,
HTTP,
)
svc.enable_dedup()
svc.data_source(
"templates",
load_templates,
description="Notification templates for the selected tenant",
)

@svc.action("send_inapp")
async def send_inapp(ctx, payload: SendInAppInput) -> SendInAppResult:
...

asyncio.run(svc.run())

HTTP ingress ownership

HTTP uses the canonical /v2/<service>/inbound path automatically.

When you need a different path, use HTTP.at("/custom/path") or HTTP.at("https://...").

For both forms, the SDK publishes the absolute HTTP endpoint by using:

  • TRIGGERS_HTTP_PUBLIC_BASE_URL when it is set
  • otherwise TRIGGERS_HTTP_ADDR (default :8081)

Real services in this repo now use bare 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.

TriggersSettings

Most production services can rely on env defaults directly:

svc = Service("notify")

Use settings=TriggersSettings(...) when you need a test or example-local override without mutating the real process env. That includes the intentional HTTP exception: the canonical path still comes from bare HTTP, while TriggersSettings(http_public_base_url=...) can override the published absolute endpoint for a narrow example or test.

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

VarUsed forWhen to set it
TRIGGERS_NATS_URLNATS registration, heartbeats, broadcasts, and NATS ingressRequired when the service runs in the real fleet
TRIGGERS_NATS_CREDS_PATHOptional NATS auth fileOnly when the NATS cluster requires creds
TRIGGERS_KAFKA_BROKERSKafka ingress wiring and canonical-topic ensureOnly when code declares KAFKA
TRIGGERS_KAFKA_INGRESS_TOPIC_PARTITIONSCanonical Kafka ingress topic partitionsOptional override; default 1
TRIGGERS_KAFKA_INGRESS_TOPIC_REPLICATION_FACTORCanonical Kafka ingress topic replication factorOptional override; default 1
TRIGGERS_KAFKA_INGRESS_TOPIC_RETENTION_MSCanonical Kafka ingress topic retention in msOptional override; default 604800000
TRIGGERS_HTTP_ADDRHTTP bind address and fallback advertised baseUsually set for HTTP ingress; local default is :8081
TRIGGERS_HTTP_PUBLIC_BASE_URLPublic HTTP base used in the manifestOnly when the advertised URL should differ from TRIGGERS_HTTP_ADDR
TRIGGERS_SERVICE_VERSIONManifest/runtime version stringRecommended in CI and shared environments
TRIGGERS_REDIS_URLFinal Redis URLFastest local-dev option and highest-precedence runtime input
TRIGGERS_REDIS_URL_SECRET_NAMEKey Vault secret name containing the full Redis URLUse when platform stores the full URL as one secret
TRIGGERS_REDIS_HOSTLiteral host[:port] or redis[s]://... baseUse when the platform exposes host separately
TRIGGERS_REDIS_HOST_SECRET_NAMEKey Vault secret name for host/baseRecommended repo pattern in Kubernetes when host is secret-backed
TRIGGERS_REDIS_PASSWORDLiteral Redis passwordUse only with host-based composition
TRIGGERS_REDIS_PASSWORD_SECRET_NAMEKey Vault secret name for Redis passwordRecommended repo pattern in Kubernetes when password is secret-backed
TRIGGERS_REDIS_DBRedis DB suffix when composing a URL from host/password inputsSet it only when the chosen Redis host does not already include a DB path
KEY_VAULT_URLAzure Key Vault base URL for any *_SECRET_NAME lookupRequired whenever any Redis secret-name var is set

If the service enables enable_dedup() or enable_rate_limit(), 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: 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:

ServiceEnvironmentSuggested Redis wiring
notify-senderspark-dev1TRIGGERS_REDIS_HOST_SECRET_NAME=spark-dev-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-dev-redis-password, TRIGGERS_REDIS_DB=3
notify-senderspark-prod-mexico1TRIGGERS_REDIS_HOST_SECRET_NAME=spark-mexico1-prod-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-mexico1-prod-redis-password, TRIGGERS_REDIS_DB=3
spark_bonusspark-dev1TRIGGERS_REDIS_HOST_SECRET_NAME=spark-dev-redis-host, TRIGGERS_REDIS_PASSWORD_SECRET_NAME=spark-dev-redis-password, TRIGGERS_REDIS_DB=5
spark_bonusspark-prod-mexico1TRIGGERS_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

  1. await svc.run() starts cleanly with no ServiceError.
  2. build_manifest() shows the expected service_sources, transports, and supports_nodes.
  3. A harness or real broker test can drive at least one success path and one failure path.