Workflow Architecture¶
Long-running operations (approvals, external CA requests, webhooks, notifications) are executed asynchronously by the workflows2_worker process. This keeps protocol responses fast and allows retries, manual intervention, and external system integration.
Workflow Execution Flow¶
flowchart TB
EVENT["Triggering event / enrollment, renewal, revocation, operator action"]
DISPATCH["Workflow dispatch service / select matching definitions / create instance"]
EVENT --> DISPATCH
DISPATCH --> DB[("PostgreSQL / workflow state")]
DB --> QUEUE["Workflow job queue / status: queued, running, blocked, done"]
WORKER["workflows2_worker / separate container process"]
WORKER -->|Claim with lease| QUEUE
WORKER --> EXECUTE{Execute step}
EXECUTE -->|Approval| APPROVAL["Approval step / status: awaiting_approval / operator action via UI"]
EXECUTE -->|Webhook| WEBHOOK["HTTP webhook call / retry on failure"]
EXECUTE -->|Email| MAIL[SMTP notification]
EXECUTE -->|PKI operation| PKI_OP["Certificate issuance / revocation, CRL update"]
EXECUTE -->|Logic| LOGIC["Condition evaluation / variable assignment"]
APPROVAL --> DB
WEBHOOK --> DB
MAIL --> DB
PKI_OP --> DB
LOGIC --> DB
DB --> NEXT{More steps?}
NEXT -->|Yes| QUEUE
NEXT -->|No| TERMINAL["Terminal state / completed, failed, canceled"]
Workflow Components¶
1. Workflow Definitions¶
Location: trustpoint/workflows2/definitions/ (YAML files)
Purpose: Define reusable workflow templates
Structure: YAML files with events, steps, conditions, and actions
Compilation: YAML compiled to internal representation (IR), stored in Workflow2Definition model
Module: workflows2/services/definitions.py
2. Dispatch Service¶
Purpose: Match events to workflow definitions and create instances
Module: workflows2/services/dispatch.py
Process:
Event occurs (e.g., device enrollment request)
Query matching workflow definitions
Create
Workflow2Instancefor each matchCreate initial
Workflow2Jobin queued state
3. Job Queue¶
Model: Workflow2Job
Key fields:
status:queued,running,done,failedlocked_until: Lease expiry timestamplocked_by: Worker ID holding leaseretry_count: Number of retry attemptslast_error: Last error message
Job lifecycle: queued → running → done (or failed → queued for retry)
Lease mechanism:
Worker claims job with 30-second lease (default)
Heartbeat extends lease for long-running steps
Stale jobs (lease expired) recovered by worker
4. Worker Process¶
Command: python manage.py workflows2_worker
Container: trustpoint-worker
Implementation: workflows2/services/worker.py
Worker loop:
Recover stale jobs (lease expired)
Claim up to batch_limit jobs
Process each job
Create next job if more steps remain
Failure handling:
Failed jobs retry with exponential backoff (1m, 2m, 4m, 8m, 16m, 32m max)
Max retries: 6 (configurable)
Error message stored in
last_error
Stale job recovery:
Query jobs with
status=runningandlocked_until < now()Mark as
failedwith “Lease expired” errorSchedule retry
5. Runtime Service¶
Purpose: Execute workflow steps and maintain execution state
Module: workflows2/services/runtime.py
Key responsibilities:
Load workflow IR (internal representation)
Execute one step at a time (checkpointed execution)
Evaluate conditions and expressions
Handle approval steps
Persist execution state after each step
6. Execution Engine¶
Module: workflows2/engine/executor.py
Supported step types:
Step Type |
Purpose |
Key Features |
|---|---|---|
set |
Variable assignment |
Template expressions, context variables |
logic |
Conditional branching |
If/then/else, condition evaluation |
approval |
Manual approval gate |
Timeout support, approval groups, status tracking |
webhook |
HTTP webhook call |
Retry on failure, custom headers, timeout |
Email notification |
Template support, SMTP integration |
|
pki.* |
PKI operations |
Certificate issuance, revocation, CRL generation |
Approval mechanism:
Sets instance status to
awaiting_approvalCreates
Workflow2ApprovalrecordWorker pauses execution
Operator approves/rejects via web UI
Worker resumes after resolution
7. Approval Mechanism¶
Model: Workflow2Approval
Key fields:
status:pending,approved,rejected,expiredrequested_by: User who initiated workflowresolved_by: User who approved/rejectedresolved_at: Resolution timestampresolution_note: Optional justification
Approval UI: workflows2/views/approvals.py
Timeout handling: Django-Q2 scheduled task checks expired approvals
Worker Deployment¶
Command-Line Options¶
Option |
Default |
Description |
|---|---|---|
|
hostname |
Worker identifier |
|
30 |
Job lease duration |
|
10 |
Batch size per tick |
|
1.0 |
Sleep between ticks |
|
- |
Run one tick and exit (debug) |
Multiple Workers¶
Multiple worker containers can run concurrently for:
Parallel job processing
High availability (worker failures don’t block queue)
Horizontal scaling
Coordination: PostgreSQL row-level locking (SELECT FOR UPDATE), lease-based job ownership
Worker Monitoring¶
Heartbeat:
Workers write heartbeat every 5 seconds
Stale heartbeats (>60s old) indicate crashed worker
Metrics:
Jobs claimed/processed/skipped per tick
Stale jobs recovered
Current queue depth
Workflow vs Scheduled Tasks¶
Trustpoint uses two separate background processing systems:
Aspect |
Workflow Engine ( |
Scheduled Tasks (Django-Q2 |
|---|---|---|
Purpose |
Long-running, event-driven operations |
Periodic maintenance tasks |
Execution |
Job queue, lease-based |
Scheduled (cron-like) |
Container |
Separate worker container |
Web container |
Features |
Approval gates, retry with backoff |
Simple retry logic |
Use cases |
Device onboarding approvals, external CA requests, webhooks |
CRL generation, certificate expiry checks, cleanup |
Example Workflows¶
Device Onboarding with Approval¶
Steps:
Validate device (check IDevID)
Request approval from operators (24h timeout)
Issue certificate
Notify ERP via webhook
Email administrator
Certificate Renewal¶
Steps:
Check device is active
Renew certificate
Notify device contact via email
Certificate Revocation¶
Steps:
Revoke certificate
Regenerate CRL
Notify monitoring system via webhook
Best Practices¶
Keep steps atomic - Each step should be idempotent
Use approval gates wisely - Only for operations requiring human judgment
Implement retry logic - External calls should be retryable
Monitor queue depth - Alert when queue grows beyond normal
Set appropriate timeouts - Prevent workflows from blocking indefinitely
Log workflow context - Include sufficient detail for troubleshooting
Handle failures gracefully - Define fallback steps and error handling
Troubleshooting¶
Issue |
Solution |
|---|---|
Queue not processing |
Check worker container status, logs, PostgreSQL connection, heartbeats |
Jobs failing repeatedly |
Check |
Approvals not appearing |
Verify |
Slow job processing |
Increase worker batch size, add more workers, optimize queries |
Stale jobs accumulating |
Increase lease duration, investigate crashes, check for deadlocks |