> For the complete documentation index, see [llms.txt](https://help.glpi-project.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.glpi-project.org/tutorials/fr/notifications/queuednotification-analysis.md).

# Analyser la "queuednotification" memory\_limit

Cette procédure d’analyse devrait vous aider à déterminer quel ticket/objet dans GLPI génère un problème CRITIQUE de **memory\_limit** atteinte lors de l’exécution de l’action automatique “**queuednotification**”.

***

## Exemple d’erreur dans le php-errors.log

```php
[2026-07-17 04:00:09] glpi.CRITICAL:   *** Fatal Error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 9269800 bytes)
  Backtrace :
  ./src/DBmysql.php:596                              

[2026-07-17 09:38:27] glpi.CRITICAL:   *** Uncaught PHP Exception Symfony\Component\ErrorHandler\Error\OutOfMemoryError: "Error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 4775392 bytes)" at DBmysql.php line 596
  Backtrace :
  ./src/DBmysql.php:596
```

Il convient d’exécuter ces requêtes SQL sur la base GLPI en erreur.

***

## Vue d'ensemble : taille totale de la file (queuednotification)

```sql
SELECT COUNT(*) AS nb,
       ROUND(SUM(LENGTH(COALESCE(body_html,''))+LENGTH(COALESCE(body_text,'')))/1048576,1) AS total_mb,
       MAX(sent_try) AS max_retry
FROM glpi_queuednotifications WHERE is_deleted = 0;
```

**Interprétation** :

* **nb** = combien de mails en attente (une file qui grossit sans cesse est un symptôme).
* **total\_mb** = poids brut cumulé de tous les body HTML/text (si ça se compte en centaines de Mo, c'est cohérent avec un **`memory_limit`** atteint).
* **max\_retry** élevé (>3-5) indique des mails qui échouent en boucle et repassent dans le batch à chaque cron, ce qui aggrave le problème de base.

Exemple concret de résultat inquiétant :

![](/files/68c9efceeaa374347d04013ef3b2fa8e6b0b4cbc)

***

## Les 20 plus grosses notifications en attente

```sql
SELECT id, itemtype, items_id, event, recipient, sent_try, create_time,
       ROUND(LENGTH(COALESCE(body_html,''))/1048576,2) AS html_mb
FROM glpi_queuednotifications
WHERE is_deleted = 0
ORDER BY LENGTH(COALESCE(body_html,'')) DESC LIMIT 20;
```

**Interprétation** :

* **html\_mb** : si une ou plusieurs lignes à plusieurs Mo (5-15 Mo), c’est certainement l’**`items_id`** associé qui provoque l’erreur.
* **itemtype/items\_id** : donne le ticket (ou autre objet) fautif à aller inspecter.

Exemple concret de résultat pas normal pour l’**`items_id`** 5557 :

![](/files/a69943c60909c2232e473ca09d8a6790510636f6)

***

## Quel ticket/objet génère le plus de volume (body × destinataires)

```sql
SELECT itemtype, items_id, event, COUNT(*) AS nb_dest,
       ROUND(SUM(LENGTH(COALESCE(body_html,'')))/1048576,1) AS mb
FROM glpi_queuednotifications
WHERE is_deleted = 0
GROUP BY itemtype, items_id, event
ORDER BY mb DESC LIMIT 10;
```

**Interprétation** :

* **nb\_dest** élevé (10, 20, 30...) combiné à un **mb** élevé = fortes chances que ça soit l’**`items_id`** qui provoque l’erreur.

Exemple concret de résultat pas normal pour l’**`items_id`** 5557 :

![](/files/95af294230a7fba2b3b34624c074a40c87f4006e)

***

## Simuler le prochain batch du cron

```sql
SELECT ROUND(SUM(LENGTH(COALESCE(body_html,''))+LENGTH(COALESCE(body_text,'')))/1048576,1) AS mb_next_batch
FROM (SELECT body_html, body_text FROM glpi_queuednotifications
      WHERE is_deleted = 0 AND mode = 'mailing' AND send_time <= NOW()
      ORDER BY send_time ASC LIMIT 50) q;
```

**Interprétation** :

* Si **mb\_next\_batch** dépasse \~100-150 Mo, le prochain cron va probablement re-crasher (le facteur multiplicateur mysqli buffered + copie PHP peut tripler ce chiffre en mémoire réelle).
* Si le résultat est bas mais que le crash persiste, c'est le signe que le batch a changé entre deux exécutions (nouveaux mails arrivés, ou **`sent_try`** qui a fait remonter d'autres lignes), il faut rejouer la requête juste avant/après le crash pour comparer.

Exemple concret de résultat pas normal :

![](/files/026b93bea8cafaa42ac799a31a82cad6ce57612b)

***

## Consultation du ticket incriminé

Une fois le ticket candidat au crash détecté en SQL, on peut tout de suite aller le consulter (en SQL ou UI), il y a de fortes chances qu’on détecte tout de suite le problème, exemple ici +6000 suivis (ça peut aussi être des images très lourdes dans les suivis/descriptions) :

![](/files/d2c729c9207fc99c159d96fa924a708398ace410)

Autant de suivis est typique d'une boucle de réponses automatiques : un expéditeur avec un répondeur automatique (out-of-office, mail marketing, accusé de réception...) répond à chaque notification GLPI, le collecteur transforme chaque réponse en suivi, qui déclenche une notification, qui provoque une nouvelle réponse automatique, etc.

Chaque nouveau suivi ré-embarque tout l'historique cité, d'où des notifications de plusieurs Mo qui finissent par faire exploser la mémoire du cron.

***

## Nettoyer le ticket

Avec des milliers de suivis, la suppression via l'interface risque elle aussi de dépasser le **`memory_limit`**.

On supprime donc d'abord les suivis directement en base :

**Vérifier d'abord le volume :**

```sql
SELECT COUNT(*)
FROM glpi_itilfollowups
WHERE itemtype = 'Ticket' AND items_id = <ID_DU_TICKET_DETECTE>;
```

**Puis supprimer :**

```sql
DELETE FROM glpi_itilfollowups
WHERE itemtype = 'Ticket' AND items_id = <ID_DU_TICKET_DETECTE>;
```

Une fois les suivis purgés, le ticket redevient manipulable dans l'interface : le mettre alors à la corbeille puis le purger définitivement depuis GLPI (et non en SQL), afin que GLPI nettoie proprement toutes les données liées (acteurs, documents, notifications en file...).

Il faut aussi penser à purger les notifications encore en attente pour ce ticket si les requêtes de la file en montrent encore.

***

## Nettoyer le collecteur

Se connecter à la boîte e-mail utilisée par le collecteur et supprimer les mails de la boucle encore présents (y compris dans les dossiers d'archivage/refus configurés).

{% hint style="danger" icon="trash" %}
Sans ça, le prochain passage du collecteur réimportera les messages et la boucle pourra éventuellement repartir.
{% endhint %}

***

## Adapter le moteur de règles du collecteur

Dans **`Administration`** *>* **`Règles`** *>* **`Règles pour assigner un ticket créé via un collecteur de mails`**, vérifier que les règles par défaut de rejet des réponses automatiques sont bien actives, et les compléter selon le cas rencontré.

Les critères utiles :

* en-tête ***Auto-Submitted*** différent de ***no*** (standard RFC 3834, couvre la majorité des répondeurs) ;
* en-têtes ***X-Auto-Response-Suppress*** ou ***X-Autoreply*** présents ;
* expéditeur de type no-reply@, newsletter@, mailer-daemon\@... ;
* sujet contenant les motifs observés dans la boucle (dans notre exemple un objet marketing récurrent).

L'action associée : **refuser le ticket sans notification** (surtout pas de réponse automatique de rejet, qui relancerait la boucle).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.glpi-project.org/tutorials/fr/notifications/queuednotification-analysis.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
