node-orchestrator
node-orchestrator
In sintesi
Motore di workflow inter-servizio: registra moduli esterni che dichiarano i propri task, persiste i workflow (grafi diretti di task con connessioni e mapping dati), distribuisce le esecuzioni tramite NATS e tiene traccia in PostgreSQL dello stato di ogni step. Adotta il pattern thin modules, smart hub: la logica orchestrale (retry, parallelismo per livelli, propagazione errori, sagas) sta nell'hub; i moduli si limitano a esporre i propri handler. È il cuore dell'automazione del tenant ditta.
Funzionalità principali
- Registry di moduli con heartbeat, healthcheck periodico e marcatura automatica come "unhealthy" quando un modulo smette di rispondere
- Persistenza workflow versionata su PostgreSQL, con clone, import/export, validazione strutturale (cicli, task orfani, schemi I/O incompatibili) e cambi di stato (draft/active/archived)
- Esecuzione asincrona dei workflow su NATS: dispatching dei task ai moduli per nome, attesa reply, calcolo del livello successivo eseguibile in parallelo
- Data mapping tipizzato fra step (template
{a} {b}, concat, condizioni, dot-notation per campi annidati) - Trigger pluggabili: schedulati (via
node-scheduler), webhook esterni, eventi NATS interni - Audit completo delle esecuzioni: timeline degli eventi, log strutturati, statistiche di durata per task/livello, progress in tempo reale via SSE
- Sagas per compensazione su fallimento di task non idempotenti
- Cache distribuita Redis opzionale per i dataset di modulo più richiesti
Architettura
Stack: Fastify v5 · Inversify (DI con constructor injection) · PostgreSQL via driver pg · NATS (con JetStream opzionale) · Redis · @pzeta/fastify-utils (auth, security, healthcheck, OpenAPI plugins) · @pzeta/log per logging strutturato.
Layout DDD (src/):
| Layer | Contenuto |
|---|---|
domain/ | Workflow (aggregate root), value object, errori, factory, eventi di dominio |
application/ | Servizi orchestrali (WorkflowService, ExecutionService, RegistryService, ExecutionLoggerService), sagas, trigger manager |
infrastructure/ | DatabaseService, MessagingService (NATS), CacheService (Redis), WebhookNotifier, SSEBridge |
presentation/ | Controllers, route plugins (WorkflowRoutes, ExecutionRoutes, RegistryRoutes, WebhookRoutes, DiagnosticsRoutes), middleware RBAC |
Pattern adottati: thin modules / smart hub, Repository, Saga, Circuit Breaker sul dispatching NATS, Event Sourcing parziale per la timeline delle esecuzioni.
RBAC: ogni route dichiara uno scope minimo (viewer, operator, admin) via requireScope(). Gli scope vengono letti dal token dell'authenticatore (fastify.authenticate() registrato da @pzeta/fastify-utils).
Casi d'uso
- Pipeline di import dati: trigger schedulato → step di download da
node-storage→ validazione XML vianode-xmlvalidation→ import in DB vianode-postgrest-sidecar→ notifica completamento vianode-notification - Generazione documenti batch: trigger webhook esterno → fan-out su N occorrenze → ciascuna invoca
node-renderer+node-print→ archiviazione sunode-storage - Reazione a eventi di dominio: un workflow è sottoscritto a
workflow.events.task.failed.>per innescare compensazioni o alert operativi - Export dati ricorrente: scheduler attiva un workflow che usa
node-excel-exportsu un dataset PostgREST e deposita l'output sunode-storagecon notifica a fine job - Workflow interattivi: il frontend Vue chiama
POST /executionsper avviare un workflow ad-hoc e si sottoscrive via SSE alla timeline di esecuzione per mostrare il progresso
Identità & esposizione
| Campo | Valore |
|---|---|
| Categoria | orchestration |
| Versione cluster | 1.0.0 |
| Image | gitea.pzetatouch.it/pzeta_touch/node-orchestrator:1.0.10 |
| URL pubblico | https://ditta.pzeta.it/orchestrator |
| Path regex ingress | `/orchestrator(/ |
| Rewrite a backend | /$2 |
| DNS interno | node-orchestrator-ditta.ditta.svc.cluster.local:3000 |
| Auth nginx | auth_request → node-user-auth |
| Repository | node-orchestrator |
| Endpoint REST | 44 (vedi sezione "API reference") |
Endpoint operazionali
Endpoint convenzionali esposti da tutti i microservizi PZeta basati su @pzeta/fastify-utils:
| Path pubblico | Scopo |
|---|---|
https://ditta.pzeta.it/orchestrator/health | liveness probe |
https://ditta.pzeta.it/orchestrator/ready | readiness probe |
https://ditta.pzeta.it/orchestrator/metrics | metriche Prometheus |
https://ditta.pzeta.it/orchestrator/api-docs.json | spec OpenAPI runtime (richiede OPENAPI_EXPOSE_IN_PRODUCTION=true) |
https://ditta.pzeta.it/orchestrator/api-docs | Swagger UI (solo in NODE_ENV !== production) |
Configurazione
Variabili d'ambiente che un integratore deve conoscere (per la lista completa vedi .env.example del repo):
| Variabile | Ruolo |
|---|---|
DATABASE_HOST / _PORT / _USER / _PASSWORD / _NAME | Connessione PostgreSQL — workflow, esecuzioni, log |
DATABASE_SCHEMA | Default nodeorchestrator; un workflow può accedere ad altri schemi via PostgREST sidecar |
NATS_URL | URL del cluster NATS; obbligatorio |
NATS_NAMESPACE | Prefisso applicativo dei subject (default orchestrator) |
NATS_JETSTREAM_ENABLED | Se true, le esecuzioni usano JetStream per delivery garantita |
REDIS_ENABLED | Abilita la cache distribuita per i dataset; off in dev |
API_KEYS | Coppie key:user:scopes per autenticazione M2M (dev e moduli locali) |
L'orchestrator espone Swagger UI solo se NODE_ENV !== production e /api-docs.json runtime solo se OPENAPI_EXPOSE_IN_PRODUCTION=true.
Note eventing NATS
Il servizio si comporta come consumer puro del proprio dominio: si sottoscrive a sei subject pattern (workflow.events.execution.*, workflow.events.task.*, workflow.events.level.completed.>) per popolare la timeline e gli aggregati di ExecutionLoggerService. Il pubblicatore di questi eventi è il modulo che esegue il task: l'orchestrator riceve la conferma asincrona via NATS invece di un polling.
Le request/reply verso i moduli registrati avvengono su subject derivati dal manifest del modulo (non statici, quindi non compaiono nello scanner statico). Quando JetStream è abilitato il dispatching è at-least-once con deduplica per executionId.
Dipendenze e dipendenti
Dipende da (servizi che questo servizio chiama):
Consumato da (chi chiama questo servizio):
frontend Vuenode-scheduler
Infrastruttura (PostgreSQL, NATS, Redis, MinIO) non è elencata qui — vedi sezione Architettura del singolo servizio.