# Incidente sessioni Ajax VTE — 17 settembre 2026

Resoconto della sessione di diagnosi e intervento su **vte_fossi** (https://vte.fossi.it) e **vtenext / 3SMB** (https://crm.3smb.it).

---

## 1. Segnalazione

L’istanza Fossi risultava **rallentata per Serena e Fabio dalla loro sede**.

- Dalla postazione di Gabriele, con utente **admin**, il CRM era fluido.
- Serena e Fabio riferivano che **gli altri siti** dalla stessa sede andavano normalmente.
- Ipotesi iniziale: **sessioni Ajax**.

Utenti coinvolti Fossi: `serena` (id 10), `fabio` (id 11). Entrambi loggati dall’IP sede `79.1.231.17`. Admin dalla rete `91.255.12.79`.

---

## 2. Diagnosi

Ipotesi confermata: **lock / leak del contatore di sessione VTE** (`$_SESSION['session_count']` in `include/VteSession.php`), non un problema di rete della sede.

### Come funziona (e perché si rompe)

VTE (`VteSession`) tiene un contatore di richieste Ajax aperte sulla stessa sessione PHP:

1. All’avvio di ogni request: `session_count++`
2. In `onShutdown`: `session_count--`
3. Se il contatore raggiunge `$maxRequests`, la nuova request **aspetta** fino a `$maxWaitTimeout` e poi continua

Se una request muore prima dello shutdown (timeout IMAP Messaggi, abort del browser, tab chiusa, **coda PHP-FPM**), il `--` non avviene. Il contatore **non si auto-ripara**.

Il buco vero: dopo il timeout VTE **continuava senza azzerare** il contatore. Da quel momento **ogni click/Ajax aspettava il timeout** (5 s con le patch Google, 30 s nel default VTE).

Default VTE (prima delle patch): `maxRequests = 5`, `maxWaitTimeout = 30`. Già 6 Ajax contemporanee congelavano la pagina per 30 secondi.

### Valori misurati il 17/09 ~11:13

| Istanza | Utente | `session_count` | Sessione aperta da |
|---|---|---|---|
| Fossi | **fabio** | **20 / 20** | 11 settembre (6 giorni, mai logout) |
| Fossi | **serena** | **20 / 20** | 17/09 09:06 |
| Fossi | admin | 7 / 20 | 17/09 10:56 (fresca) |
| 3SMB | **Jasmine** | **20 / 20** | 17/09 09:23 |
| 3SMB | DoctorCare | 10 / 20 | 17/09 10:33 |
| 3SMB | sara@3smb.it | 1–2 / 20 | ok |

Per questo 3SMB “dichiarava i soliti problemi”: stesso bug, più utenti, stesso collo di bottiglia PHP.

Serena dopo il primo reset è risalita da 1 a **16 in ~15 minuti**: il leak si riempiva di continuo.

### Cosa non era

- Non la rete della sede (altri siti ok; admin da un’altra rete era ok perché aveva una sessione fresca).
- Non il plugin Google come causa. Serena e Fabio hanno **`google_sync_enabled = 0`**.
- Contributi secondari: modulo Messaggi (IMAP Aruba `imaps.aruba.it:993` sulla casella `info@fossi.it` per entrambi), `CheckSession` ogni 10 s, reminder, tab multiple, sessione Fabio mai chiusa dal 11/09.

---

## 3. È un errore di programmazione? È Google?

**Sì, è un bug del core VTE** (`VteSession`): contatore non crash-safe e nessun self-heal dopo il timeout.

**GoogleSyncPlus non crea il problema.** È un amplificatore (più Ajax) e un cerotto parziale:

- Alza il tetto 5→20 e taglia l’attesa 30s→5s (già presente su Fossi e 3SMB).
- Le sue Ajax `get_config` / `check_sync_status` non incrementano `session_count`.
- Aveva un auto-reset, ma **solo** se l’utente apre il widget Calendario Google. Serena/Fabio non lo usano, quindi non li ha mai sbloccati.
- Su **MTM** era già stato aggiunto il self-heal (`Resetting leaked session_count`). Su Fossi e 3SMB **mancava**.

---

## 4. Seconda causa: PHP-FPM da 5 worker condivisi

Fossi e 3SMB usavano lo **stesso pool** `www` di PHP 7.4 con `pm.max_children = 5`.

Cinque processi per due CRM in produzione (3SMB: ~10 utenti, BPM, posta). Quando i worker sono pieni le Ajax vanno in timeout, il contatore vaza, e il bug VTE si innesca da solo.

PHP 8.3 (solo MTM) è un pool a parte e non c’entra.

RAM server: 9.7 GB totali, ~6.7 GB disponibili al momento dell’intervento. Worker medi ~80 MB RSS.

---

## 5. Interventi effettuati

### 5.1 Self-heal in `VteSession.php`

Applicato su **Fossi**, **3SMB** e già presente su **MTM**.

Dopo il timeout, se `session_count >= maxRequests` il contatore viene azzerato invece di restare al tetto per sempre.

File: `include/VteSession.php`.

### 5.2 Persistenza dopo upgrade VTE (plugin Google)

Creato `modules/GoogleSyncPlus/gspl_vte_session_patch.php` e agganciato a:

- `cron_sync.php` (ripristino automatico a ogni cron)
- `install.php` (step 16)
- `health_check.php` (verifica anche il leak-reset)

Istanze: Fossi, 3SMB, MTM.

**Non serve reinstallare/OTA/ricollegare Google** per questo incidente.

### 5.3 Reset immediato dei contatori leakati

| Istanza | Utente | Azione |
|---|---|---|
| Fossi | fabio, serena | 20 → 1 (poi di nuovo ~16 → 1 quando risalivano) |
| 3SMB | Jasmine | 20 → 1 |
| 3SMB | DoctorCare | 10 → 1 |

I login restano validi: non è stato fatto logout forzato.

### 5.4 Pool PHP-FPM separati

Script (CRLF corretto al secondo tentativo):

```bash
sudo bash /home/gabriele/vte-php74-pools/apply.sh
```

Esito 17/09 11:32: **OK**.

| Sito | Pool | Socket | Worker ora / max |
|---|---|---|---|
| https://vte.fossi.it | `fossi` | `/run/php/php7.4-fpm-fossi.sock` | 3 / **12** |
| https://crm.3smb.it | `vtenext` | `/run/php/php7.4-fpm-vtenext.sock` | 4 / **20** |
| phpMyAdmin / resto | `www` | `/run/php/php7.4-fpm.sock` | 2 / 5 |
| https://vte.mtm-movimentoterra.it | PHP 8.3 (invariato) | `php8.3-fpm.sock` | — |

Verifica routing Apache:

- `vte.fossi.it` → PID sul pool **fossi**
- `crm.3smb.it` → PID sul pool **vtenext**

File di config:

- `/etc/php/7.4/fpm/pool.d/fossi.conf`
- `/etc/php/7.4/fpm/pool.d/vtenext.conf`
- `/etc/apache2/conf-available/zz-vte-php74-pools.conf` (enabled)
- sorgenti e `apply.sh`: `/home/gabriele/vte-php74-pools/`

---

## 6. Plugin Google: cosa fare

**Niente**, per questo incidente.

Non serve:

- Install / OTA da Impostazioni GoogleSyncPlus
- Ricollegare i calendari
- Logout/login per Google

Nota **separata** (non causa della lentezza): su Fossi il cron Google per **admin** logga `Sync error: no valid OAuth token`. Impatta solo il sync calendario di admin. Se serve, ricollegare OAuth da Impostazioni; altrimenti si può lasciare.

---

## 7. Come si presenta all’utente

Prima: CRM “lento” solo per chi aveva la sessione satura (ogni click ~5 s), sede irrilevante se non perché lì stavano Serena/Fabio/utenti 3SMB.

Dopo il self-heal: non si resta congelati per sempre. Se il contatore tocca ancora 20, **una** request aspetta fino a 5 s e poi il contatore si azzera.

Dopo i pool FPM: Fossi e 3SMB non si calpestano più; il refill del contatore dovrebbe essere molto più raro.

Se qualcuno sente ancora un colpo di ~5 s isolato: chiudere tab extra del CRM e, se la sessione è aperta da giorni (caso Fabio), un logout/login pulisce lo stato.

---

## 8. File toccati (riepilogo)

**Core VTE**

- `/var/www/html/vte_fossi/include/VteSession.php`
- `/var/www/html/vtenext/include/VteSession.php`
- MTM: già presente, non modificato in questa sessione per il leak-reset

**GoogleSyncPlus** (Fossi, 3SMB, MTM)

- `modules/GoogleSyncPlus/gspl_vte_session_patch.php` (nuovo)
- `modules/GoogleSyncPlus/cron_sync.php`
- `modules/GoogleSyncPlus/install.php`
- `modules/GoogleSyncPlus/health_check.php`

**Sistema**

- pool PHP 7.4 `fossi` / `vtenext` + conf Apache `zz-vte-php74-pools`
- `/var/www/html/vte_fossi/.cursorrules` (nota operativa §8.3)

**Non modificato:** `config.inc.php`.

---

## 9. Cronologia breve

| Ora (Europe/Rome) | Evento |
|---|---|
| ~11:06 | Segnalazione lentezza Serena/Fabio dalla sede; ipotesi sessioni Ajax |
| ~11:13 | Conferma `session_count=20` su fabio e serena; admin a 7 |
| ~11:14 | Reset contatori Fossi + self-heal su `VteSession` Fossi |
| ~11:21 | Richiesta fix definitivo anche per 3SMB e FPM |
| ~11:24–11:27 | Self-heal 3SMB, helper GSPL persistente, Jasmine 20 e DoctorCare 10 azzerati |
| ~11:31 | Primo `apply.sh` fallito per CRLF (`set: pipefail`) |
| ~11:32 | Secondo `apply.sh` OK: pool separati attivi |
| ~11:35 | Verifica routing Apache → pool corretti |
| ~11:38 | Chiarito: nessuna azione sul plugin Google |

---

## 10. Follow-up eventuali

- Monitorare per 1–2 giorni se Serena/Fabio e 3SMB restano fluidi.
- Se un upgrade VTE riscrive `VteSession.php`, il cron GoogleSyncPlus deve rimettere tetto, timeout e leak-reset (verificare il health check).
- OAuth admin Fossi: solo se serve il sync Google di quell’utente.
- Non alzare ulteriormente i worker senza guardare la RAM: tetto attuale 12+20+5 ≈ 37 processi, ~3 GB se tutti pieni a ~80 MB.
