Passa al contenuto principale

Destinazioni

Flowlyze supporta due modalità distinte di gestione della destinazione dati attiva e passiva consentendo una flessibilità elevata nell'integrazione con sistemi esterni e nella definizione delle strategie di elaborazione.

Panoramica

Le modalità di gestione delle destinazioni sono due:

  • Attiva (push): Flowlyze invia i dati direttamente alla destinazione e garantisce la consegna.
  • Passiva (pull): Flowlyze mette i dati a disposizione tramite una coda, e un sistema esterno li preleva autonomamente.

La scelta tra le due modalità dipende dalle esigenze di integrazione e dalla responsabilità che si vuole attribuire a ciascun sistema.

Gestione attiva

Nella gestione attiva, Flowlyze invia i dati direttamente alla destinazione configurata e si occupa di garantirne la consegna corretta.
Il sistema monitora ogni invio, gestisce eventuali tentativi di ritrasmissione e applica meccanismi di conferma per assicurarsi che il dato raggiunga effettivamente il target. In questa modalità Flowlyze agisce come componente responsabile dell'affidabilità del trasporto, riducendo la complessità a carico dei sistemi esterni.

Gestione passiva

Nella gestione passiva, Flowlyze funge da produttore di dati e li mette a disposizione tramite una coda o un meccanismo analogo. I messaggi vengono importati e mantenuti in attesa finché un sistema esterno non li elabora autonomamente, seguendo un modello simile al pattern publisher-subscriber.

Il sistema che consuma i dati effettua letture accompagnate da un acknowledge, tramite il quale notifica l'avvenuta ricezione al fine di garantire un flusso affidabile e una corretta gestione dello stato dei messaggi.

Destinazione HTTP

La destinazione HTTP di Flowlyze consente l'invio di dati verso sistemi esterni tramite richieste HTTP, una per ciascun messaggio presente in coda oppure una per blocco di messaggi. La richiesta viene costruita sulla base dei parametri configurati (metodo, endpoint, intestazioni, query string) mentre il body coincide con il payload JSON derivante dal singolo record.
L'esito dell'operazione è determinato esclusivamente dallo status code restituito dal sistema di destinazione: qualsiasi valore compreso tra 200 e 299 è considerato un successo.

Status Code

Qualsiasi status code HTTP compreso tra 200 e 299 viene considerato un successo. Tutti gli altri codici (3xx, 4xx, 5xx) vengono trattati come errori e attivano le politiche di retry configurate.

Parametri configurabili

La destinazione HTTP mette a disposizione i seguenti parametri, tutti modificabili:

  • URL: endpoint di destinazione della chiamata.
  • Method: metodo HTTP utilizzato (es. POST, PUT, PATCH, DELETE).
  • Headers: set di intestazioni personalizzate da includere nella richiesta.
  • Query Params: parametri di query aggiunti all'URL.

Tutti i campi di tipo stringa supportano l'uso di variabili, sia globali sia locali, permettendo una configurazione dinamica in base al contesto operativo.

Autenticazione

La destinazione HTTP supporta gli stessi protocolli di autenticazione disponibili per la sorgente HTTP (vedi sezione dedicata), consentendo un allineamento coerente delle modalità di sicurezza.

Funzionalità pianificate (TBD)

Sono previste evoluzioni per estendere la flessibilità e le capacità di trasformazione della destinazione HTTP:

  • Utilizzo dei campi del messaggio come template dinamici: Applicazione dei valori del messaggio ai parametri di URL, query e headers, con sostituzione diretta durante la generazione della richiesta.
  • Riscrittura del body: Possibilità di definire un body personalizzato senza passare per componenti low-code.
  • Interpretazione avanzata della risposta: Analisi del contenuto del body di risposta per determinare l'esito dell'operazione, superando il modello basato esclusivamente sullo status code.
  • Invio batch di messaggi: Invio di multiple entità in un'unica chiamata, con definizione del modello dati aggregato e capacità di interpretare la risposta per valutare l'esito del singolo messaggio, in modo analogo al comportamento del Custom Adapter ma senza la necessità di un protocollo predefinito.

Destinazione RDBMS

La destinazione RDBMS consente a Flowlyze di collegarsi a qualunque database relazionale accessibile pubblicamente via Internet, senza dipendenze rispetto a uno specifico vendor. È pensata per implementare scenari di sincronizzazione dati, migrazione, consolidamento o integrazione bidirezionale tra sistemi.

Parametri di connessione

Per stabilire la connessione al database, Flowlyze richiede i seguenti parametri:

  • URL del server
  • Porta
  • Username
  • Password

La correttezza della connessione può essere verificata direttamente tramite l'apposita funzione di test disponibile nella schermata di configurazione.

Definizione delle query di scrittura

Flowlyze offre una gestione molto granulare delle operazioni SQL grazie a tre tipologie di query che coprono l'intero ciclo di elaborazione:

Ciclo di elaborazione SQL

Le tre fasi (PREPARE → INSERT → FINALIZE) permettono di implementare logiche complesse:

  • PREPARE: preparazione ambiente (tabelle temporanee, pulizia)
  • INSERT: scrittura dati per ogni record
  • FINALIZE: consolidamento e operazioni finali (upsert, stored procedure)

INSERT STATEMENT

Eseguito per ogni riga del set di dati. Consente di utilizzare uno statement SQL parametrico, dove i campi del record sono accessibili tramite:

  • @nomecampo
  • @nomecampo_sottocampo per oggetti annidati

Generalmente questo statement è usato per eseguire INSERT, ma può essere qualunque comando SQL valido.

PREPARE STATEMENT

Eseguito prima dell'elaborazione di un batch.
Permette operazioni preparatorie come:

  • creazione di tabelle temporanee,
  • pulizia o inizializzazione di strutture dati,
  • generazione di ambienti intermedi per la scrittura.

FINALIZE STATEMENT

Eseguito dopo l'inserimento di tutte le righe del batch.
È tipicamente utilizzato per:

  • consolidare i dati nelle tabelle definitive,
  • eseguire upsert,
  • richiamare stored procedure,
  • effettuare ricalcoli o operazioni di normalizzazione.

Esempio 1 — Scrittura in modalità insert or update

Questo esempio illustra un flusso di sincronizzazione clienti in cui un messaggio JSON viene trasformato in una riga della tabella relazionale **CUSTOMER**. Flowlyze esegue la query per ogni record in coda, mappando i campi del messaggio sui campi della tabella. L'obiettivo è dimostrare come un'integrazione semplice possa comunque supportare logiche più complesse come l'upsert (insert or update).

Struttura dati (diagramma Mermaid)

In questo modello:

  • Il cliente è rappresentato da un'unica tabella CUSTOMER.
  • I dati dell'indirizzo sono appiattiti in colonne dedicate (ADDRESSSTREET, ADDRESSCITY, ecc.).
  • Tutte le informazioni anagrafiche e di preferenza sono centralizzate in un unico record per semplificare la gestione.

Intento e motivazioni dell'esempio

L'obiettivo dell'esempio è mostrare come un singolo messaggio JSON:

{
"customer_id": "CUST-482917",
"name": "Jordan Mitchell",
"date_of_birth": "1987-03-12",
"email": "jordan.mitchell@examplemail.com",
"phone": "(415) 555-2894",
"address": {
"street": "742 Market Street",
"unit": "Apt 5B",
"city": "San Francisco",
"state": "CA",
"zip": "94103"
},
"account_status": "Active",
"signup_date": "2023-08-19",
"preferred_contact_method": "Email",
"marketing_opt_in": true,
"notes": "Customer prefers weekend delivery windows."
}

venga convertito in una riga della tabella CUSTOMER tramite il seguente SQL:

INSERT INTO CUSTOMER (
CUSTOMERID,
NAME,
DATEOFBIRTH,
EMAIL,
PHONE,
ADDRESSSTREET,
ADDRESSUNIT,
ADDRESSCITY,
ADDRESSSTATE,
ADDRESSZIP,
ACCOUNTSTATUS,
SIGNUPDATE,
PREFERREDCONTACTMETHOD,
MARKETINGOPTIN,
NOTES
) VALUES (
@customer_id,
@name,
@date_of_birth,
@email,
@phone,
@address__street,
@address__unit,
@address__city,
@address__state,
@address__zip,
@account_status,
@signup_date,
@preferred_contact_method,
@marketing_opt_in,
@notes
);

Punti chiave della mappatura:

  • I campi del messaggio sono mappati 1:1 sulle colonne della tabella.
  • I valori annidati vengono referenziati tramite notazione a dot (@address__street).
  • Il modello "flat" permette di rappresentare tutti i dati più rilevanti in una sola entità.
Notazione per oggetti annidati

Per accedere a campi annidati nel JSON, usa la notazione con doppio underscore: @oggetto__campo. Ad esempio, @address__street accede a address.street nel messaggio JSON.

Esempio 2 — Scrittura in modalità transazionale

Questo esempio mostra un flusso di sincronizzazione ordini in cui un singolo messaggio di ordine viene scomposto in più entità relazionali (cliente, indirizzi, testata ordine, righe ordine) e scritto in modo coerente e transazionale. L'obiettivo è garantire che tutti i dati correlati a un ordine vengano inseriti/aggiornati insieme, oppure tutti scartati in caso di errore.

Transazionalità

Tutte le operazioni vengono eseguite all'interno di un'unica transazione del database. Se un qualsiasi passaggio fallisce, l'intera transazione viene rollbackata, garantendo la coerenza dei dati.

Struttura dati

Come leggere il modello:

  • CUSTOMER rappresenta il cliente che effettua l'ordine (dati anagrafici e preferenze di contatto).
  • ORDER_HEADER è la testata dell'ordine (data, stato, pagamenti, importi).
  • ORDER_ITEM rappresenta le singole righe dell'ordine (articoli acquistati).
  • ADDRESS contiene gli indirizzi collegati all'ordine (spedizione e fatturazione), associati sia al cliente sia all'ordine.

Le tabelle TMP_CUSTOMER, TMP_ORDER_HEADER, TMP_ORDER_ITEM e TMP_ADDRESS viste nello SQL sono la versione temporanea di queste stesse entità: fungono da staging area intermedia, usata per costruire un set di dati coerente prima del consolidamento sulle tabelle principali (CUSTOMER, ORDER_HEADER, ORDER_ITEM, ADDRESS).

Esempio di ordine (messaggio in ingresso)

{
"order_id": "ORD-984532",
"order_date": "2025-02-11T14:23:00Z",
"customer": {
"customer_id": "CUST-482917",
"first_name": "Jordan",
"last_name": "Mitchell",
"email": "jordan.mitchell@examplemail.com",
"phone": "+1-415-555-2894",
"alt_phone": "+1-415-555-7331",
"contact_preferences": {
"preferred_method": "Email",
"allow_sms": true,
"allow_calls": false
}
},
"items": [
{
"item_id": "SKU-10482",
"description": "Wireless Bluetooth Headphones",
"quantity": 1,
"unit_price": 89.99
},
{
"item_id": "SKU-55720",
"description": "USB-C Charging Cable 2m",
"quantity": 2,
"unit_price": 12.49
},
{
"item_id": "SKU-88410",
"description": "Laptop Sleeve 13-inch",
"quantity": 1,
"unit_price": 24.99
}
],
"shipping_address": {
"street": "742 Market Street",
"unit": "Apt 5B",
"city": "San Francisco",
"state": "CA",
"zip": "94103"
},
"billing_address": {
"street": "742 Market Street",
"unit": "Apt 5B",
"city": "San Francisco",
"state": "CA",
"zip": "94103"
},
"payment_method": "Credit Card",
"payment_status": "Paid",
"order_status": "Processing",
"currency": "USD",
"shipping_cost": 7.99,
"total_amount": 147.96,
"notes": "Leave the package at the building concierge."
}

Intento e motivazioni dell'esempio (lettura dell'SQL)

L'SQL fornito implementa una scrittura transazionale a più step, allineata con il modello di PREPARE / INSERT / FINALIZE della destinazione RDBMS.

Creazione delle tabelle temporanee (fase PREPARE)

CREATE TEMPORARY TABLE TMP_ADDRESS (...);
CREATE TEMPORARY TABLE TMP_CUSTOMER (...);
CREATE TEMPORARY TABLE TMP_ORDER_HEADER (...);
CREATE TEMPORARY TABLE TMP_ORDER_ITEM (...);

Motivazioni:

  • creare una staging area transazionale, isolata dal modello dati finale;
  • permettere di caricare e validare i dati dell'ordine (inclusi vincoli di chiave esterna tra TMP_*) prima del consolidamento;
  • mantenere il batch "autocontenuto": ogni ordine (o gruppi di ordini) viene caricato in un set di tabelle temporanee coerenti.

In termini Flowlyze, questa parte appartiene alla fase PREPARE STATEMENT.

Scrittura nelle tabelle temporanee (fase INSERT STATEMENT)

Gli INSERT INTO TMP_* mappano direttamente il JSON sulle tabelle temporanee.

Indirizzi di spedizione e fatturazione

INSERT INTO TMP_ADDRESS (...) VALUES (
@shipping_address.id,
@shipping_address.street,
...
@customer__customer_id,
@order_id
);

INSERT INTO TMP_ADDRESS (...) VALUES (
@billing_address__id,
@billing_address__street,
...
@customer__customer_id,
@order_id
);
  • Dal messaggio si estraggono due insiemi di dati (spedizione e fatturazione).
  • Entrambi gli indirizzi sono collegati allo stesso CUSTOMER_ID e ORDER_ID.
  • I placeholder (es. @shipping_address.street) rappresentano i campi del messaggio agganciati alla colonna corrispondente.
Cliente
INSERT INTO TMP_CUSTOMER (...) VALUES (
@customer.customer_id,
@customer.first_name,
@customer.last_name,
@customer.email,
@customer.phone,
@customer.alt_phone,
@customer.contact_preferences.preferred_method,
@customer.contact_preferences__allow_sms,
@customer.contact_preferences__allow_calls
);
  • Si estrae l'oggetto customer e lo si normalizza in una riga di TMP_CUSTOMER.
  • Le preferenze di contatto vengono salvate in colonne dedicate (PREFERRED_METHOD, ALLOW_SMS, ALLOW_CALLS).
Testata ordine
INSERT INTO TMP_ORDER_HEADER (...) VALUES (
@order_id,
@order_date,
@customer.customer_id,
@payment_method,
@payment_status,
@order_status,
@currency,
@shipping_cost,
@total_amount,
@notes
);
  • Collega l'ordine al cliente (CUSTOMER_ID) e contiene tutte le informazioni di pagamento e stato.
Righe ordine (loop sugli items)
{{#each items}}

INSERT INTO TMP_ORDER_ITEM (...) VALUES (
@items[{{@index}}].order_item_id,
@order_id,
@items[{{@index}}].item_id,
@items[{{@index}}].description,
@items[{{@index}}].quantity,
@items[{{@index}}].unit_price
);

{{/each}}
  • Per ogni elemento dell'array items viene generato un INSERT in TMP_ORDER_ITEM.
  • Il costrutto {{#each items}} indica un template iterativo: Flowlyze genera tanti INSERT quanti sono gli articoli nell'ordine.
  • Tutte le righe sono legate allo stesso ORDER_ID, preservando la relazione 1–N tra ordine e righe.

Questa parte costituisce la fase INSERT STATEMENT della destinazione RDBMS, eseguita per ogni messaggio.

Consolidamento nelle tabelle finali (fase FINALIZE STATEMENT)

Dopo aver popolato le tabelle temporanee, l'SQL esegue il consolidamento verso le tabelle definitive (CUSTOMER, ORDER_HEADER, ADDRESS, ORDER_ITEM) usando INSERT ... SELECT ... ON DUPLICATE KEY UPDATE.

Esempio per CUSTOMER:

INSERT INTO CUSTOMER (...columns...)
SELECT
c.CUSTOMER_ID AS EXT_ID,
c.CUSTOMER_ID,
...
FROM TMP_CUSTOMER c
ON DUPLICATE KEY UPDATE
CUSTOMER_ID = VALUES(CUSTOMER_ID),
FIRST_NAME = VALUES(FIRST_NAME),
...
;

Stesso schema per:

  • ORDER_HEADER (tabella degli ordini),
  • ADDRESS (indirizzi collegati a cliente/ordine),
  • ORDER_ITEM (righe ordine).
Motivazioni chiave:
  1. Upsert idempotente:

    • Se il record non esiste → INSERT.
    • Se il record esiste (stesso PK / chiave univoca) → UPDATE.
      Questo consente di rieseguire il flusso sullo stesso ordine senza creare duplicati, allineando la base dati allo stato più recente del sistema sorgente.
  2. Atomicità transazionale

    • Tutte le operazioni (scrittura su TMP_*, consolidamento su tabelle finali) possono essere eseguite all'interno di un'unica transazione del database.
    • Se un qualsiasi passaggio fallisce (es. errore di vincolo, dato incoerente), l'intera transazione può essere rollbackata, mantenendo i dati in uno stato consistente.
  3. Separazione tra modellazione logica e origine dati

    • Il messaggio JSON ha una struttura "orientata all'evento".
    • Il database ha una struttura relazionale normalizzata.
    • Le tabelle temporanee fungono da ponte: permettono trasformazioni, controlli, arricchimenti e gestione di vincoli prima dell'upsert definitivo.
  4. Portabilità tra RDBMS

    • La sintassi ON DUPLICATE KEY UPDATE è tipica di MySQL, ma la logica di insert or update è replicabile su altri database:

      • ON CONFLICT DO UPDATE in PostgreSQL,
      • MERGE INTO ... WHEN MATCHED / NOT MATCHED in SQL Server (MSSQL) e Oracle.
    • In Flowlyze, la struttura PREPARE / INSERT / FINALIZE resta la stessa; cambia solo il dialetto SQL usato nel FINALIZE per adattarsi al RDBMS.

Portabilità SQL

La sintassi ON DUPLICATE KEY UPDATE è specifica di MySQL. Per altri database:

  • PostgreSQL: usa ON CONFLICT DO UPDATE
  • SQL Server / Oracle: usa MERGE INTO ... WHEN MATCHED / NOT MATCHED

Flat File

La destinazione Flat File consente di esportare un set di dati in uno o più file, secondo una logica completamente disaccoppiata dal formato del file, esattamente come avviene per la sorgente Flat File.
Il flusso definisce dove scrivere (location) e come formattare i dati (format), mentre Flowlyze gestisce la serializzazione e il trasferimento verso il sistema di destinazione.

Parametri di base

La destinazione Flat File espone i seguenti parametri principali:

  • Directory: Percorso remoto in cui i file verranno creati (directory FTP/SFTP/FTPS).

  • Filename: Nome del file da generare. Supporta placeholder e variabili del flusso, permettendo la costruzione dinamica del nome (es. orders_{{date}}.csv).

  • Location Type: Indica il canale di trasferimento utilizzato (es. SFTP, FTP…).

  • Granularity: Definisce il livello di granularità della scrittura, ovvero quanti file verranno generati. La selezione imposta un suffisso che viene inserito prima dell'estensione nel FileName

    • Batch: un file per batch di esecuzione (singola esecuzione del flusso dati)
    • Daily: un file per giorno
    • RequestId: un file per gruppo di messaggi elaborati (parametro configurato nelle opzioni di BufferSize)
    • Single With Time: per singolo messaggio,
    • Single:nessuna granularità predefinita. Viene creato un file con nome FileName senza aggiunta di suffissi.
  • Connessione: Parametri di accesso al server di destinazione:

    • host
    • porta
    • username
    • password

Location Type

Attualmente la destinazione supporta tutte le varianti del protocollo FTP:

  • FTP
  • SFTP
  • FTPS
  • Amazon S3 (TBD)
  • Azure Blob Storage (TBD)

Format Type

I formati attualmente disponibili sono:

  • CSV
  • JSON

Di seguito le configurazioni specifiche per ciascuno.

Format Settings — CSV

Parametri disponibili:

  • Has headers: Indica se il file deve includere la riga di intestazione delle colonne.
  • Culture: Cultura utilizzata per la rappresentazione di numeri e date (es. it-IT → usa virgola come separatore decimale, en-US → punto decimale).
  • Delimiter: Delimitatore di colonna (,, ;, \t, …).
  • Quote: Carattere per racchiudere i campi testuali. Usare \0 per non applicare alcun quoting.

Format Settings — JSON

Parametri disponibili:

  • Array field name: Indica il nome del campo che conterrà l'array.Se valorizzato: il JSON è scritto come oggetto, es. ` { "data": [ {...}, {...} ] }`Se vuoto: viene scritto direttamente l'array in root: ` [ {...}, {...} ]`

Mapping (solo CSV)

La destinazione Flat File permette di definire una mappatura delle colonne del file CSV. Attraverso la mappatura è possibile descrivere con precisione come verrà generato ogni campo del file.

Per ciascuna colonna è possibile specificare:

  • Nome della colonna: Il nome riportato nell'intestazione (se has headers = true).
  • Valore di default: Utilizzato se il campo non è presente nel messaggio.
  • Tipo del campo: string, int, decimal, datetime (influisce sulla formattazione e sulla cultura applicata).
  • Formato del campo: Esempi:
    • #.00 per formattare decimali con due cifre,
    • yyyy-MM-dd per date.
  • Read format: Formato atteso in input, utile quando si devono convertire valori stringa in date o numeri strutturati durante la scrittura.

Custom Adapter

Oltre ai connettori standard (source e destination), Flowlyze può essere esteso tramite App esterne chiamate Custom Adapter.
Non esistono vincoli sulla tecnologia utilizzata: l'unico requisito è il supporto al protocollo HTTP, seguendo le regole definite dal protocollo di comunicazione.

Nel contesto del protocollo, il ruolo di System Integrator è svolto da Flowlyze, che invia richieste HTTP al Custom Adapter ed elabora le risposte.

Architettura e flussi di integrazione

Modalità di esecuzione

Il Custom Adapter prevede due modalità operative:

Modalità sincrona

  • Flowlyze invia i dati in batch (ad esempio 1000 righe per volta) via API.
  • Il Custom Adapter elabora il batch entro la singola chiamata HTTP e restituisce un payload standard che, per ogni messaggio, riporta:
    • esito dell'elaborazione,
    • eventuali errori e metadati.
  • La chiamata è soggetta a timeout e a limitazioni sulla durata massima (tipicamente 30 secondi).

Questa modalità è adatta a integrazioni veloci, idempotenti e con volumi limitati per singolo batch.

Modalità asincrona

  • Flowlyze invia i dati in batch come nel caso sincrono, ma il Custom Adapter può processarli in modo differito (job in background, code interne, ecc.).
  • Nella risposta iniziale il Custom Adapter segnala che l'elaborazione è asincrona.
  • Flowlyze effettua polling sul sistema di destinazione (tramite l'azione progress) fino al completamento del job.

Questa modalità è ideale per elaborazioni più pesanti o lente, dove non è realistico concludere tutto entro il timeout di una singola richiesta HTTP.

Timeout

La modalità sincrona ha un timeout tipico di 30 secondi. Se l'elaborazione richiede più tempo, utilizza la modalità asincrona.

Protocollo di comunicazione sincrono

Ogni sistema esterno che voglia ricevere dati da Flowlyze tramite Custom Adapter deve esporre uno o più endpoint HTTP.
Tutti gli endpoint condividono la stessa struttura di base del body:

{
"action": "execute",
"payload": { ... }
}
  • action: tipo di richiesta. I valori previsti sono:
    • "execute" → avvia l'elaborazione dei messaggi,
    • "progress" → (utilizzato nel flusso asincrono) richiede lo stato di avanzamento.
  • payload: contenuto specifico della richiesta, che varia in base all'azione.

Endpoint di esecuzione

`POST <dominio>/system-integrator/handler1 (action "execute")`

Questo endpoint viene chiamato da Flowlyze per consegnare un batch di messaggi da elaborare.

Request

{
"action": "execute",
"payload": {
"requestId": "<guid>",
"messages": [
{
"msgId": "<guid>",
"msg": {
"...": "..."
},
"meta": {
"...": "..."
}
}
],
"meta": {
"...": "..."
}
}
}

Significato dei campi:

  • payload.requestId Identificatore univoco della richiesta (batch) inviato da Flowlyze.
  • payload.messages Array dei messaggi da processare.
  • payload.messages[i].msgId Identificatore univoco del singolo messaggio all'interno del batch.
  • payload.messages[i].msg Payload effettivo del messaggio (record dati da elaborare).
  • payload.messages[i].meta Metadati riferiti al singolo messaggio (contesto, configurazioni specifiche, ecc.).
  • payload.meta `` Metadati condivisi da tutto il batch (es. stringhe di connessione, credenziali, endpoint downstream, parametri di configurazione).

Vincoli temporali e di esito

  • Il sistema esterno deve processare la richiesta entro 30 secondi dall'invio.
  • Obbligo HTTP 200:
    • Se il sistema risponde con uno status diverso da 200, l'intera richiesta viene considerata fallita, e tutti i messaggi del batch risultano non elaborati.
    • Le politiche di retry configurate in Flowlyze si occuperanno di reinviare il batch o i messaggi non processati, secondo configurazione.

Response sincrona

Se l'elaborazione viene gestita in modalità sincrona, il Custom Adapter risponde con:

{    
"requestId": "<requestId>",
"isAsync": false,
"messages": [
{
"msgId": "<guid>",
"status": "success",
"date": "<date>",
"meta": { }
}
]
}
  • requestId `` Deve coincidere con quello ricevuto nella richiesta.

  • isAsync false indica che l'elaborazione è stata gestita tutta all'interno di questa chiamata.

  • messages Array di esiti per ogni messaggio inviato.

  • messages[i].msgId Deve corrispondere a un msgId precedentemente inviato da Flowlyze.

  • messages[i].status Stato dell'elaborazione del singolo messaggio:

    • "success" → messaggio elaborato correttamente,
    • "error" → elaborazione fallita,
    • "in_progress" → usato solo in scenari asincroni, quando l'elaborazione non è ancora terminata.
  • messages[i].date Data/ora di fine elaborazione in formato ISO8601.

  • messages[i].meta Eventuali metadati restituiti dal sistema esterno (es. ID di risorsa creata, messaggi di errore, log sintetico).

In caso di errore di elaborazione, i messaggi con status = "error" verranno gestiti da Flowlyze secondo le policy di retry configurate (nuovi tentativi, dead-letter, logging, ecc.).

Protocollo di comunicazione asincrono

In modalità asincrona:

  1. Flowlyze invia una richiesta action = "execute" identica al caso sincrono.

  2. Il Custom Adapter:

    • risponde con HTTP 200,
    • imposta isAsync: true,
    • può marcare i messaggi come "in_progress" finché l'elaborazione non è conclusa.
  3. Flowlyze effettua chiamate successive con action = "progress" per aggiornare lo stato dei messaggi associati a uno specifico requestId.

  4. Il Custom Adapter restituisce via via lo stato aggiornato (success / error) per ogni msgId.

La struttura del body rimane allineata al contratto descritto in precedenza (stesso requestId, stessa lista messages con stato aggiornato).

Manifesto e discovery degli endpoint

Per permettere a Flowlyze di scoprire in modo dinamico quali handler sono esposti da un Custom Adapter, il sistema esterno deve pubblicare un manifesto in un endpoint ben noto.

Endpoint di discovery

**GET <dominio>/.well-known/system-integrator.json **

Risponde con un JSON della forma:

{
"version": 1,
"handlers": {
"handler1": "<dominio>/system-integrator/handler1",
"handler2": "<dominio>/system-integrator/handler2"
}
}
  • version Versione del manifesto, utilizzata per compatibilità futura.
  • handlers Mappa [nome handler] → [endpoint handler] . Ogni handler rappresenta un punto di ingresso per l'elaborazione dei dati provenienti da un subscriber/flow diverso. In questo modo, un unico Custom Adapter può servire più flussi Flowlyze con logiche dedicate.
  • handlers.<handler> URL dell'endpoint a cui Flowlyze invia le richieste execute progress relative a quello specifico handler.

Vincoli:

  • L'endpoint di discovery DEVE essere sempre esposto esattamente su /.well-known/system-integrator.json.
  • Gli URL degli altri endpoint (handler) sono liberi, a discrezione del sistema esterno; l'esempio con /system-integrator/handler1 e /system-integrator/handler2 rappresenta solo una convenzione consigliata.

Librerie

Vedi sezione Piattaforme\Custom per librerie e template di progetto

Null

La destinazione Null è una destinazione fittizia utilizzata quando non è necessario — o non è ancora disponibile — un vero sistema di destinazione.
Il suo unico scopo è ricevere i dati e registrarli nei log, senza effettuare alcuna elaborazione, trasformazione o invio verso sistemi esterni.

Questa destinazione risulta utile in diversi scenari, ad esempio:

  • fase di sviluppo o test di un flusso, quando la destinazione reale non è pronta;
  • verifica del corretto mapping e della serializzazione dei messaggi;
  • diagnosi di comportamenti anomali a monte del flusso, isolando il problema.

Flowlyze conserva il messaggio nei log interni, permettendo di confermare la corretta ricezione e di analizzare facilmente il contenuto. Nessun altro processing viene eseguito.

Uso della destinazione Null

La destinazione Null è particolarmente utile durante lo sviluppo e il debugging, permettendo di verificare che i dati arrivino correttamente al punto di destinazione senza dover configurare un sistema esterno.