ποΈ ValkyrAI Workflow Engine v2.0 β System Architecture
The N8N Killer: Built on ThorAPI, Hardened for Production
π― High-Level Architectureβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT LAYER β
β ββββββββββββββββ ββββ ββββββββββββ ββββββββββββββββ β
β β React Flow β β DLQ Browser β β Execution β β
β β Studio β β & Replay UI β β Monitor β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β ββββββββββββββββββββ΄βββββββββββββββββββ β
β β β
β RTK Query Hooks β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
β HTTPS/JSON
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REST API LAYER β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β WorkflowExecution API β Run API β DLQ API β β
β β /WorkflowExecution β /Run β /DeadLetterQueueβ β
β β - POST /{id}/execute β - POST /{id}/heartbeat β β
β β - POST /{id}/cancel β - GET /{id} β β
β β - POST /{id}/pause β β β
β β - POST /{id}/resume β /DeadLetterQueue β
β β β - POST /{id}/requeue β
β β β - POST /{id}/discard β
β ββββββββββ¬ββββββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β
β β β β β β
β Spring Security β β Spring MVC β
β RBAC + ACL β β @RestController β
βββββββββββββΌββββββββββββΌβββββββββΌβββββββββββΌββββββββββββββββββββββ
β β β β
β β β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SERVICE LAYER β
β ββββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ValkyrWorkflowExecutionService (Orchestration) β β
β β - execute(workflowId, triggerType, payload) β β
β β - pause/resume/cancel operations β β
β β - state transition management β β
β ββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββ ValkyrRunService (Idempotency Engine) β
β β ββ generateIdempotencyKey() [SHA-256] β
β β ββ acquireLease() [DB row lock] β
β β ββ updateHeartbeat() [extend lease] β
β β ββ completeRun() [store outputs] β
β β ββ failRun() [classify error] β
β β ββ reapZombieRuns() [@Scheduled 30s] β
β β β
β ββββ ValkyrDLQService (Error Recovery) β
β β ββ quarantine() [failed runs] β
β β ββ requeue() [with overrides] β
β β ββ discard() [operator notes] β
β β β
β ββββ ValkyrCircuitBreakerService (Resilience) β
β β ββ isCircuitOpen() β
β β ββ recordFailure() β
β β ββ openCircuit() / closeCircuit() β
β β β
β ββββ ValkyrRunnerService (Execution Engine) β
β ββ pollAndExecute() [@Scheduled 100ms] β
β ββ executeWithHeartbeat() β
β ββ enforceResourceLimits() β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ValkyrBudgetService & ValkyrQuotaService β β
β β - checkBudget() [kill switch] β β
β β - checkQuota() [rate limits] β β
β β - trackCost() [per-principal] β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
β JPA/Hibernate
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REPOSITORY LAYER β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ValkyrRunRepository (Custom Queries) β β
β β - findByIdempotencyKey() [O(1) lookup] β β
β β - findByLeaseUntilBefore() [zombie detection] β β
β β - findByStateOrderByCreated() [FIFO queue] β β
β β - findRunsReadyForRetry() [auto-retry] β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ValkyrDLQRepository (DLQ Queries) β β
β β - findByResolution() β β
β β - countByResolution() β β
β β - findByFailureType() β β
β ββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββ β
β β
β + WorkflowExecutionRepository, BudgetRepository, β
β QuotaRepository, CircuitBreakerStateRepository β
βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
β JDBC
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA LAYER β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PostgreSQL Database (ACID Transactions) β β
β β β β
β β Tables: β β
β β - workflow_execution (state tracking) β β
β β - run (idempotency + lease) β β
β β - dead_letter_queue (quarantine) β β
β β - circuit_breaker_state (resilience) β β
β β - budget (cost control) β β
β β - quota (rate limiting) β β
β β β β
β β Indexes: β β
β β - idx_run_idempotency (UNIQUE) β β
β β - idx_run_lease_until (zombie reaper) β β
β β - idx_run_state (queue polling) β β
β β - idx_dlq_resolution (operator queries) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β‘ Execution Flow: End-to-Endβ
ββββββββββββ
β USER β POST /WorkflowExecution/{workflowId}/execute
β CLIENT β {params: {...}}
ββββββ¬ββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WorkflowExecutionController β
β ββ @PreAuthorize("hasPermission(...)") β
β ββ workflowExecutionService.execute(...) β
ββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ValkyrWorkflowExecutionService β
β ββ Create WorkflowExecution (PENDING β RUNNING) β
β ββ Load Workflow.tasks β
β ββ For each Task: β
β ββ runService.createRun(execution, task, inputs, 1) β
β ββ Store Run (PENDING state) β
ββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β (Async polling loop β RunnerService)
β
ββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β ValkyrRunnerService [@Scheduled(fixedDelay = 100ms)] β
β ββ runService.findPendingRuns(limit=10) β
β ββ For each pending Run: β
β ββ runService.acquireLease(runId, runnerId) β
β β ββ Check existing lease holder β
β β ββ Set leaseUntil = now + 2min β
β β ββ Set state = LEASED β
β β ββ Save Run β
β β β
β ββ Start heartbeat thread (every 10s): β
β β ββ runService.updateHeartbeat(runId, runnerId) β
β β ββ Verify lease ownership β
β β ββ Extend leaseUntil β
β β ββ Update heartbeatAt β
β β β
β ββ circuitBreakerService.isCircuitOpen(module)? β
β β ββ YES β failRun(CIRCUIT_OPEN) β
β β ββ NO β continue β
β β β
β ββ budgetService.checkBudget(principal)? β
β β ββ EXCEEDED β failRun + kill switch β
β β ββ OK β continue β
β β β
β ββ quotaService.checkQuota(principal, resource)? β
β β ββ EXCEEDED β failRun β
β β ββ OK β continue β
β β β
β ββ Execute VModule: β
β β ββ Load ExecModule β
β β ββ module.execute(inputs) β outputs β
β β ββ Track duration & cost β
β β β
β ββ On SUCCESS: β
β β ββ runService.completeRun(runId, outputs, ...) β
β β ββ state = SUCCESS β
β β ββ Store outputs, duration, cost β