AGLANCIO - Scheduler multi-istanza sincronizzazione AreaGate¶
Identificazione¶
| Campo | Valore |
|---|---|
| Programma | AGLANCIO |
| Righe | 2.276 |
| Versione | 2.10.0 (28/04/2026) - vedi Versioni AGLANCIO |
| Versione script | 0003 |
| Tipo | Subroutine (mmsubw.cpy), always-on, ciclo continuo |
| Interfaccia | cobol AGLANCIO istanza_NN (parametro LINKAGE) |
Funzione¶
AGLANCIO e' lo scheduler di sincronizzazione che orchestra l'esecuzione di 138 programmi SWN* tra il gestionale Eurocoge (file COBOL indicizzati) e il database PostgreSQL KPN utilizzato da AreaAPP (mobile/web).
Opera come demone multi-istanza: piu' copie (0-99) possono girare in parallelo, ciascuna responsabile di un sottoinsieme di processi.
Parametri di avvio¶
cobol AGLANCIO istanza_NN
Il parametro LINKAGE aglancio-linkage (pic x(20)) contiene "istanza_NN". Il programma estrae il numero di istanza (0-99) dalla posizione 9:2.
Se il parametro non viene passato (1 solo argomento), l'istanza viene impostata a 0.
Istanze e classi¶
Assegnazione automatica¶
All'avvio (m-cerca-istanze-attive), AGLANCIO forza automaticamente le istanze in base all'ID del processo:
| Range ID processo | Istanza forzata | Tipo |
|---|---|---|
| 0 - 39.999 | 0 (se modo=T e istanza >= 80) | Standard ad intervalli |
| 0 - 39.999 | 80 (se modo=O e istanza < 80) | Standard a orari fissi |
| 40.000 - 49.999 | 90 | Processi particolari |
| 50.000 - 50.999 | 92 | Database Sw-ing |
| 51.000 - 51.999 | 99 (se istanza = 0) | Database Frontiera |
| 90.000 - 99.999 | 91 | Processi custom |
Istanze speciali¶
| Istanza | Caratteristica | Note |
|---|---|---|
| 0 | Standard | Processi ad intervalli normali |
| 80-89 | Orari fissi | Ignorano lo standby orario |
| 90 | Particolari | ID 40000-49999 |
| 91 | Custom | ID 90000-99999 |
| 92 | Sw-ing | DB secondario, ignora standby |
| 99 | Frontiera | DB frontiera, ignora standby |
Ciclo principale¶
Schema completo¶
m-00 (startup)
+-- Parsing parametro istanza
+-- ctr-abil
+-- gesdebug-apri-principale
+-- Imposta path files di controllo (controllo/)
+-- Imposta nomi file: spegni, alive, check, version, verlancio, istanze
+-- Verifica se chiamato da GESSTPRC (agprg-called)
+-- open-files, rd-azi
+-- Crea file FVERSION con k-versione-x-script
+-- Carica versione script lancio_ambienti (FVERLANCIO)
+-- Avvia thread m-keep-alive
MAIN LOOP (perform until m-richiesto-spegnimento = "S"):
+-- db-test-connection
| +-- Chiude DB esistente
| +-- Rilegge configurazione (x99-src-cfg: 6 parametri COGCNF)
| +-- Apre connessione PostgreSQL (SWGETS + sql-init)
| +-- Se OK: db-open-tables (check version su 5 tabelle)
|
+-- Se connessione OK:
| +-- Se ciclo iniziale:
| | +-- m-aggiorna-runtime-version
| | +-- m-cerca-istanze-attive (scan ARPPROC, crea file FISTANZE)
| |
| +-- m-ciclo-principale
| | +-- m-leggi-dati-arpazien (standby, switch ON/OFF, sleep)
| | +-- carica-ed-esegui-processi (core del ciclo)
| | +-- leggi-aggiorna-data-ora-check (keepalive, statistiche)
| |
| +-- Se fl-richiesto-reload = "S": reimposta ciclo iniziale
| +-- Altrimenti: fl-ciclo-iniziale = "N" (se non in standby)
|
+-- Se cfg-aglancio-close-db = "S": chiude DB
+-- C$SLEEP (tm-cfg-aglancio-sleep secondi, default 5-3600)
+-- m-test-spegnimento (verifica file aglancio-spegni-NN.txt)
fine:
+-- db-close-tables
+-- gesdebug-chiudi
+-- z-close-files
+-- cancel "POSTA"
+-- exit program
Logica di business dettagliata¶
Caricamento ed esecuzione processi (carica-ed-esegui-processi)¶
Questo e' il cuore della logica di business.
1. Se ciclo iniziale: log "Eseguo il ciclo iniziale"
2. Registra data/ora inizio ciclo (tm-dc-ini-data/ora)
3. CHECK STANDBY:
a. Verifica fascia oraria (tm-standby-inizio / tm-standby-fine)
- Gestisce il cambio giorno (es. 23:15 - 05:00)
- Istanze 80-89, 92, 99 ignorano lo standby orario
b. Verifica giorno della settimana (tm-standby-gg-week: stringa 7 chars)
- Tutti i giorni applicano lo standby giornaliero
c. Se in standby: esce senza eseguire nulla
4. Se ciclo iniziale: ciclo-check-disponibilita
(verifica per ogni processo se il .cob esiste su disco)
5. CICLO PROCESSI (m-ciclo-processi):
Loop su ARPPROC (sequenziale, ID < 100.000):
Per ogni processo:
a. Legge/crea ARPSTPRC (stato runtime)
b. Filtra per istanza corrente (a-stpr-istanza = w-aglancio-istanza)
c. Conta processi totali
d. Se non disponibile (fl-disp = "N"): skip
e. Se attivo (fl-att = "S") o forzato (forzo-ese = "S"):
- Conta processi attivi
- check-tempo-attesa -> fl-is-timeout?
- Se timeout: call-a-stpr-prg (esegue il processo)
* IMPORTANTE: dopo l'esecuzione, riprende dal processo successivo
(w-id-processo-start = a-proc-id + 1) e rientra nel loop
esterno (fl-ciclo-terminato). Questo gestisce il caso in cui
un processo SWN apre un secondo DB e invalida il cursore.
6. Aggiorna ISTANZESYNC con contatori processi
7. Calcola durata ciclo (COGS62) e logga
Verifica tempo di esecuzione (check-tempo-attesa)¶
Due modalita' di scheduling:
Modo T (Intervalli)¶
Prossima = ultima_esecuzione + N_minuti
- Confronta w-tempo-sched (ARPSTPRC sched-data/ora) con w-tempo-attuale
- Se w-tempo-sched <= w-tempo-attuale -> timeout
- Tempo default se non configurato: 60 minuti
Modo O (Orari fissi)¶
1. Scansiona ARPPRCSCHED per tutte le righe del processo
2. Per ogni schedulazione attiva (fl-canc <> "C", fl-attiva <> "N"):
- calcola-tempo-sched-ipotetico:
a. Prende ora schedulazione (a-prcs-ora)
b. Se ora < ora attuale: sposta al giorno successivo
c. Se day-of-week <> 0: avanza fino al giorno giusto
d. Se day-of-month <> 0: avanza fino al giorno del mese
- Seleziona la schedulazione piu' vicina (minimo ipotetico)
3. Se nessuna schedulazione trovata: processo non eseguito
Lancio processo (call-a-stpr-prg)¶
1. Log: "Innesco processo PROG (NOME - Operazione: OPE)"
2. Pre-esecuzione:
- Imposta ARPSTPRC: stato = "I" (in corso), forzo-ese = "N"
- Salva date precedenti in prec-data/prec-ora
- Imposta att-data/ora = data/ora corrente
- Aggiorna ISTANZESYNC: ultimo-id-avviato = a-proc-id
3. Prepara util-agprg:
- agprg-esporta-tutto = da ARPSTPRC
- agprg-ope = a-proc-operazione
- agprg-id-processo = a-proc-id
4. Se istanza con DB secondario: stop thread keep-alive
5. CALL a-proc-prg USING stringhe util-agprg
ON OVERFLOW -> log errore critico (es2000)
CANCEL a-proc-prg
6. Se istanza con DB secondario: riavvia thread keep-alive
7. Post-esecuzione:
- Calcola durata processo (COGS62)
- Aggiorna ARPSTPRC:
* stato = "A" (in attesa)
* att-data/ora = data/ora corrente
* Calcola prossima esecuzione
* Reset esporta-tutto = "N"
* Statistiche: durata-ultimo, n-cicli-oggi, durata-tot-oggi, durata-media-oggi
* Se cambio data: sposta oggi -> ieri, azzera oggi
- Aggiorna ISTANZESYNC: ultimo-id-eseguito = a-proc-id
Calcolo prossima esecuzione ad intervalli¶
COGS62: data_attuale + (tempo_attesa * 60 secondi) = prossima data/ora
Calcolo prossima esecuzione a orari fissi¶
Per ogni riga ARPPRCSCHED:
1. Parti da data/ora ultima esecuzione
2. Se a-prcs-ora >= ora_attuale: usa oggi con a-prcs-ora
Altrimenti: sposta al giorno successivo
3. Se day-of-week specificato: avanza fino a quel giorno (loop GESDATE)
4. Se day-of-month specificato: avanza fino a quel giorno del mese
5. Risultato: data/ora ipotetica
Seleziona il minimo tra tutte le ipotetiche -> prossima esecuzione
Gestione standby¶
Standby orario¶
- RAZI-STANDBY-INIZIO (HHMM) / RAZI-STANDBY-FINE (HHMM)
- Gestione cambio giorno:
Se inizio > fine (es. 2315 > 0500):
standby se ora >= inizio OR ora <= fine
Se inizio <= fine (es. 1200 < 1500):
standby se ora >= inizio AND ora <= fine
- Istanze 80-89, 92, 99: standby orario ignorato
Standby giornaliero¶
- RAZI-GG-WEEK-STOP: stringa 7 caratteri ("1234567")
Ogni carattere rappresenta un giorno (1=Lun...7=Dom)
Se il giorno corrente e' presente -> standby
- Si applica a TUTTE le istanze (nessuna eccezione)
Gestione spegnimento¶
Da file (m-test-spegnimento)¶
1. Cerca file aglancio-spegni-NN.txt
2. Se esiste:
- m-richiesto-spegnimento = "S" (interrompe il main loop)
- Cancella file spegni
- Cancella file alive
- NON cancella file version
- Log "Richiesto spegnimento da remoto"
Da DB (switch ON/OFF in leggi-aggiorna-data-ora-check)¶
Legge ARPAZIEN.razi-switch-onoff:
- "ON": attivazione da AreaGate
-> razi-attiva-sincro = "S", cfg-attiva-areaapp = "S"
-> Aggiorna COGCNF locale
- "OFF": spegnimento da AreaGate
-> razi-attiva-sincro = "N", cfg-attiva-areaapp = "N"
-> Aggiorna COGCNF locale
- In entrambi i casi: reset razi-switch-onoff = " "
Reload (razi-aglancio-reload)¶
Se razi-aglancio-reload = 1:
- fl-richiesto-reload = "S" -> il main loop reimpostera' ciclo iniziale
- Verifica e aggiorna sleep se cambiato da remoto
- razi-aglancio-reload = 2 (flag di conferma)
Gestione keepalive¶
Thread keep-alive (m-keep-alive)¶
Thread background in loop infinito:
1. Sleep per tm-cfg-aglancio-sleep secondi
2. Lock thread (thread safety)
3. Set priorita' a 10
4. Crea cartella controllo (C$MAKEDIR) se non esiste
5. Verifica spegnimento rapido: se m-richiesto-spegnimento = "S" -> esce
6. Crea/verifica file aglancio-alive-NN.txt (heartbeat)
7. Crea/verifica file aglancio-check-NN.txt (status marker)
8. Unlock thread
Nota: il commento nel codice (righe 684-700) discute la possibilita' di forzare lo stop-run dal thread keep-alive quando AGLANCIO e' bloccato in un sottoprocesso. Questa funzionalita' e' stata disabilitata per il rischio di corruzione dati.
Statistiche¶
Per istanza (ISTANZESYNC)¶
Ad ogni fine ciclo:
- a-ist-n-cicli-oggi += 1
- a-ist-durata-tot-oggi += durata_ultimo_ciclo
- a-ist-durata-media-oggi = totale / n_cicli
- Keepalive: data/ora corrente
Al cambio data: - Sposta oggi -> ieri - Salva in AGLSTORICOISTANZA (storico giornaliero) - Azzera contatori oggi
Per processo (ARPSTPRC)¶
Ad ogni esecuzione:
- a-stpr-durata-ultimo = secondi
- a-stpr-n-cicli-oggi += 1
- a-stpr-durata-tot-oggi += durata
- a-stpr-durata-media-oggi = totale / n_cicli
- Minimo durata = 1 secondo (evita divisioni per zero)
Tabelle database (PostgreSQL KPN)¶
In lettura/scrittura¶
| Tabella | Operazioni | Campi chiave |
|---|---|---|
| ARPAZIEN | Read/Rewrite | razi-azi (PK). Config globale: attiva-sincro, standby, switch-onoff, sleep, reload, versioni |
| ARPPROC | Read sequenziale | a-proc-id (PK). Catalogo processi: prg, nome, des, modo-sched, tempo-std, operazione, padre-id |
| ARPSTPRC | Read/Write/Rewrite | a-stpr-id + a-stpr-azi (PK). Stato runtime: fl-attivazione, stato (A/I), att/sched/prec data-ora, tempo-attesa, direzione, esporta-tutto, forzo-ese, errori, statistiche |
| ARPPRCSCHED | Read sequenziale | a-prcs-id + a-prcs-azi + a-prcs-ora + a-prcs-day-of-week + a-prcs-day-of-month. Schedulazioni orarie fisse |
| ISTANZESYNC | Read/Write/Rewrite | a-ist-azi + a-ist-istanza (PK). Keepalive, contatori, versione, ultimo processo avviato/eseguito, fl-spenta, statistiche giornaliere |
| AGLSTORICOISTANZA | Read/Write/Rewrite | a-agsi-azi + a-agsi-istanza + a-agsi-data (PK). Snapshot giornaliero statistiche |
File COBOL¶
| File | Utilizzo |
|---|---|
| COGCNF | Configurazione locale (via RNEWCONF) |
| FEURTAB | Tabella ausiliari (COGFILES) |
File di controllo¶
Directory: ext-arc-dir/controllo/
| File | Suffisso istanza | Creato da | Funzione |
|---|---|---|---|
aglancio-alive-NN.txt |
Si | Keep-alive thread | Heartbeat (creato/verificato ogni ciclo) |
aglancio-check-NN.txt |
Si | Keep-alive thread | Status marker |
aglancio-spegni-NN.txt |
Si | GESSTPRC | Trigger spegnimento (letto e cancellato) |
aglancio-version.txt |
No | AGLANCIO | k-versione-x-script ("0003") |
aglancio-istanze.txt |
No | AGLANCIO/GESSTPRC | Elenco numeri istanze attive |
lancio-ambienti-version.txt |
No | Script esterno | Versione script di lancio |
aglancio-istanze.error |
No | Script esterno | Trigger per reload istanze |
Configurazione (COGCNF via RNEWCONF)¶
| Pack | Gruppo | Chiave | Tipo | Default |
|---|---|---|---|---|
| C | areaapp | cod-azienda | Stringa(6) | - |
| C | abilita | attiva-areaapp | S/N | - |
| C | areaapp | db-log-level | Numerico(2) | - |
| C | areaapp | aglancio-sleep-seconds | Numerico(6) | 5 se 0 |
| C | AREAAPP | AGLANCIO-ATTIVO | S/N | - |
| C | AREAAPP | AGLANCIO-CLOSE-DB | S/N | - |
La stringa di connessione DB viene recuperata tramite CALL "SWGETS".
Copybook e moduli¶
Copybook specifiche¶
| Copybook | Contenuto |
|---|---|
| aglancio.select | SELECT per file di servizio |
| aglancio.fd | FD record file |
| aglancio.wrk | Working-storage con dati runtime, SQL, processi |
| aglancio.decla | DECLARATIVES gestione I/O |
| aglancio.prc | Procedure SQL per tabelle PostgreSQL |
Copybook standard¶
wstato, wopenf, wgrave, wnscr, cogazien, utils62, utilswgets, utilgesdate, utilgesdebug, utilncnf, utilagprg, l-copiaf, k-tipi-cogtabel, k-personal
Chiamate esterne¶
| Programma | Funzione |
|---|---|
| RNEWCONF | Lettura configurazione |
| SWGETS | Stringa connessione DB |
| COGS62 | Calcolo differenze temporali |
| GESDATE | Operazioni su date (info, somma giorni) |
| COPIAF | Verifica esistenza file programma (.cob) |
| GESDEBUG | Logging strutturato con prefisso istanza |
| C$SLEEP | Pausa tra i cicli |
| C$NARG | Conteggio argomenti linkage |
| C$MAKEDIR | Creazione cartella controllo |
| POSTA | Notifiche (cancellato in chiusura) |
| SWN* | I 138 programmi di sincronizzazione (CALL dinamico via a-proc-prg) |
Logging¶
AGLANCIO utilizza GESDEBUG con un override locale (local-gesdebug-linkage-common) che antepone il prefisso di istanza a ogni messaggio:
I-0: Messaggio... (istanza 0)
I-5: Messaggio... (istanza 5)
I99: Messaggio... (istanza 99)
Livelli: S=trace, E=errore, W=warning, I=info, CRITICO (es2000).
L'istanza 99 (w-istanza-debug) produce logging aggiuntivo a livello trace per ogni processo esaminato.
Diagramma di sequenza - Lancio processo¶
AGLANCIO ARPPROC ARPSTPRC SWN_XXX ISTANZESYNC
| | | | |
|--- Read next -->| | | |
|<-- processo ----| | | |
| |--- Read ------>| | |
| |<-- stato ------| | |
| | | | |
| [check: istanza? attivo? timeout?] | |
| | | | |
|--- Rewrite: stato="I" --------->| | |
|--- Rewrite: ultimo-id-avviato --|---------------|--------------->|
| | | | |
|--- CALL --------|----------------|-------------->| |
| | | |--- sync --> |
|<-- return ------|----------------|---------------| |
| | | | |
|--- Rewrite: stato="A" --------->| | |
| + prossima esecuzione | | |
| + statistiche | | |
|--- Rewrite: ultimo-id-eseguito -|---------------|--------------->|
| | | | |
Note implementative¶
-
Ciclo a ripresa: dopo l'esecuzione di un processo SWN che apre un DB secondario, il cursore su ARPPROC viene invalidato. Per questo il ciclo esterno (
m-ciclo-processi) riprende daw-id-processo-start = a-proc-id + 1, gestendo il caso in cui un solo processo viene eseguito per iterazione. -
Thread keep-alive: gira in background con priorita' 10 e crea i file di heartbeat. Se AGLANCIO e' bloccato in un SWN, il keep-alive continua a funzionare (tranne per istanze con DB secondario dove viene fermato).
-
Check disponibilita' programmi: al ciclo iniziale, verifica per ogni processo se il file
.cobesiste su disco (COPIAF fileinfo). Aggiornaa-stpr-processo-disponibiledi conseguenza. -
Gestione sleep = 0: se il tempo di sleep non e' configurato, AGLANCIO lo segnala come errore critico e usa un fallback di 120 secondi.
-
Script lancio_ambienti: AGLANCIO collabora con uno script esterno che gestisce il lancio e il monitoraggio delle istanze. La comunicazione avviene tramite i file nella cartella controllo.
-
DB secondario: le istanze 92 e 99 originariamente usavano un DB separato (
w-istanza-db-secondario). Il codice per fermere il keep-alive e' ancora attivo, ma il flagw-istanza-db-secondarioe' forzato a "N" (commentato il codice che lo impostava a "S").
Cache processi (ottimizzazione)¶
A partire dalla modifica di aprile 2026, il ciclo processi utilizza una cache in working storage (w-cache-processi, max 1000 entry) che memorizza i dati di ARPSTPRC e ARPPROC. La cache viene popolata una sola volta nel paragrafo m-cerca-istanze-attive tramite x-popola-cache-processo e riutilizzata in m-ciclo-processi tramite x-copia-cache-su-a-stpr. Dopo l'esecuzione di ogni processo, la cache viene aggiornata da x-aggiorna-cache-dopo-esec.
Questo evita scansioni ripetute delle tabelle remote (ARPPROC, ARPSTPRC) ad ogni ciclo dello scheduler, migliorando le prestazioni in scenari con molti processi configurati. In caso di overflow (>1000 processi), viene emesso un log critico e i processi in eccesso non vengono caricati.