flow-action-worker
Responsibility
Section titled “Responsibility”flow-action-worker consumes references to action jobs that were committed with
measurements. Job identity is flowExecutionId + actionNodeId + outputIndex;
redelivery therefore cannot create a second logical job.
E-mail jobs resolve the most specific Device, Device Type or Tenant recipient
binding. A specific disabled binding stops without fallback. The worker pins
recipients, active logical template version, and sanitized rendered content
before sending. Handlebars uses strict mode and a small helper allowlist.
Unescaped output, prototype access, Partials, Partial Blocks, Decorators,
Decorator Blocks, and Subexpressions are rejected from the parsed syntax tree at
both the API and worker boundary. Nodemailer cannot read files or URLs while
building messages. The worker supplies only sender, recipients, subject, plain
text, optional sanitized HTML, and a fixed message ID to sendMail(). A
deterministic Message-ID reduces but cannot eliminate duplicates after an
ambiguous SMTP acknowledgement.
Test and production use authenticated Office 365 client submission on port 587.
SENS_SMTP_AUTH_REQUIRED=true makes the username/password pair mandatory when
Actions are enabled, while SENS_SMTP_REQUIRE_TLS=true rejects delivery unless
STARTTLS succeeds. This Basic Authentication path is temporary and must be
replaced by OAuth before Microsoft’s final removal. Behavior remains unchanged
through December 2026, is then disabled by default with temporary admin
re-enablement for existing tenants, and receives its announced final removal
date in the second half of 2027.
Current Device Values are committed by flow-worker together with
Measurements and never pass through this Action worker. Replays do not produce
E-mail action jobs.
Kill switch and failures
Section titled “Kill switch and failures”With SENS_FLOW_ACTIONS_ENABLED=false, the process does not consume the durable
stream, so jobs remain pending. A disabled tenant control stores jobs as
paused and acknowledges broker delivery without increasing attempts. Resume
atomically restores pending and creates one outbox event per job.
E-mail admission uses a PostgreSQL minute bucket per tenant, so multiple worker
replicas share one limit. A full bucket defers the job to the next window without
an attempt. Delivery and dependency failures use durable job status plus delayed
outbox events; broker redelivery is reserved for failures before a durable
decision. After SENS_FLOW_ACTION_MAX_ATTEMPTS, the job becomes
dead_lettered. Committed Current Values and Measurements are never rolled
back by a later E-mail failure.
The worker exposes standard health, readiness, version, logs, and metrics. Logs exclude recipient lists and rendered message bodies.