DAG Pipelines for Custom CPQ
“Make complex persistence explicit as a dependency graph.”
Make complex persistence explicit as a dependency graph.
What Made the Problem Difficult
Custom Configure, Price, Quote (CPQ) implementations often involve deeply relational data models (Quotes, Quote Lines, Option Groups, Attributes, Tiered Adjustments, and Taxation Records) that must be calculated, validated, and saved atomically.
Core Platform Constraint
Naive persistence routines rely on tangled imperative Apex scripts, trigger cascades, and arbitrary execution order, leading to cyclic dependencies, governor limit breaches, partial commit failures, and race conditions during save operations.
- !Save workflow must execute across multiple dependent stages in strict mathematical order
- !Data outputs from upstream operations must feed cleanly into downstream calculation stages
- !Failure at any pipeline stage must trigger deterministic rollback and clear failure diagnostics
- !Must scale gracefully as new CPQ calculation rules, validations, and integrations are introduced
What System Was Designed
Modeled the entire custom CPQ save lifecycle as an explicit Directed Acyclic Graph (DAG). Each discrete operation (payload normalization, line item calculation, tax resolution, and DML persistence) is represented as a discrete node. The engine performs topological sorting to determine optimal execution order, executes independent parallel stages where possible, and guarantees atomic transactional integrity.
Pivotal Architectural Choices
Key Architectural Decisions
Explicit DAG Pipeline Framework vs. Chained Trigger Handlers
Implicit trigger execution order in Salesforce makes debugging multi-object save failures notoriously fragile.
- Trigger-handler frameworks with static boolean flags
- Monolithic procedural Apex service class
Makes execution order visible, prevents cyclic dependencies by design, and ensures strict separation between orchestration and individual business operations.
Immutable Pipeline Context Container vs. Mutable SObject References
Passing mutable record references across multiple service classes leads to unexpected side-effects and data corruption.
- Global static state variables
- In-place record mutation across stages
Guarantees referential transparency and allows individual pipeline nodes to be unit tested in complete isolation.
What Was Actually Built
Constructed a lightweight graph representation data structure supporting adjacency list dependency definitions.
Implemented a topological sort algorithm (Kahn's algorithm) to validate graph acyclicity and establish deterministic stage ordering.
Designed an immutable execution context carrying state, stage inputs, and validation diagnostics throughout the pipeline.
Added compile-time and initialization-time circular dependency detection to prevent runtime deadlocks.
Built granular error boundary handling at each node with detailed telemetry logging for failed validation rules.
Deliberate Architectural Compromises
Trade-offs & Mitigations
⚖Formal Graph Abstraction Overhead vs Direct Scripting Simplicity
Complete elimination of cyclic save bugs and effortless extensibility as business rules evolve.
Engineers must model operations as discrete nodes rather than writing inline procedural Apex.
Developed a fluent pipeline builder API simplifying node registration and dependency chaining.
⚖Deferred Single-Turn Bulkified DML vs Incremental Stage Writes
Drastically conserves DML statements and eliminates partial-commit rollback complexities.
Accumulates record modifications in Apex memory throughout pipeline execution.
Strict heap monitoring and lightweight DTO representations during calculation phases.
Verified Outcomes
Eliminated cyclic dependency errors and intermittent save failures across custom CPQ operations
Decoupled complex pricing and validation calculations from database persistence mechanisms
Allowed engineering squads to add new calculation and validation steps safely without touching existing code
Save transaction duration and transaction failure rate metrics: [VERIFY WITH KULDEEP]
System Schematic & Data Flow
Save workflow modeled as a DAG: Node A normalizes ingress, forking into independent calculation stages B and C, converging into atomic DML persistence at Node D.
Text alternative for screen readers: Architecture flow: Node A: Ingress Normalization to Node B: Line Calculation via Dependency Edge 01; Node A: Ingress Normalization to Node C: Tax Resolution via Dependency Edge 02; Node B: Line Calculation to Node D: Atomic Persistence via Calculated Lines Join; Node C: Tax Resolution to Node D: Atomic Persistence via Surcharges Join
Architectural Conclusion
“Complex CPQ persistence becomes easier to reason about when the workflow itself becomes an explicit graph.”
- •As software systems grow in complexity, implicit execution order becomes the number one source of platform instability.
- •Making workflow dependencies explicit in code transforms chaotic enterprise persistence into a deterministic, evolvable pipeline.