Среднее время решения измеряет тех, кто уже покинул очередь. Средний возраст заявок измеряет тех, кто всё ещё в ней, — и именно там живёт забытый бэклог. В этом руководстве показано, откуда берётся это число в GLPI, почему одно лишь среднее вводит в заблуждение, как отделить возраст от застоя и как превратить это в еженедельную процедуру разбора бэклога в средах, которые мы сопровождаем.
Что измеряет средний возраст — и что он скрывает
Средний возраст заявок — это среднее число дней между созданием и сегодняшним днём, учитывающее только заявки, которые остаются открытыми. В отличие от среднего времени решения, которое видит только уже решённое, он фиксирует текущее состояние очереди. Проблема в том, что среднее само по себе — плохое обобщение реальной очереди: типичный бэклог бимодален — десятки новых заявок возрастом в несколько часов соседствуют с хвостом заявок, стоящих неделями. Масса новых заявок тянет среднее вниз и скрывает как раз старые, которые вам и нужно найти. Поэтому среднее никогда не используется в одиночку: его сопровождают распределение и медиана.
Откуда берётся это число в GLPI
Всё хранится в таблице glpi_tickets. Возраст использует столбец date (дата создания); выборка «открытых» использует status. Важные статусы:
1— Новая (ещё не отсортирована)2— В работе (назначена)3— В работе (запланирована)4— В ожидании (ожидание третьей стороны)5— Решена и6— Закрыта (вне бэклога)
Самая частая ошибка здесь — сваливать в одну кучу всё, что не 5 и не 6. Заявки в статусе В ожидании (статус 4) законно стоят в ожидании поставщика, клиента или запчасти — они раздувают средний возраст, хотя никто ничего не забыл. Сегментация по статусу — первый честный фильтр:
-- Average age by status (segment: "Pending" inflates the average)
SELECT
status,
ROUND(AVG(DATEDIFF(NOW(), date)), 1) AS avg_age_days,
COUNT(*) AS total
FROM glpi_tickets
WHERE status NOT IN (5, 6) -- exclude Solved and Closed
AND is_deleted = 0
GROUP BY status
ORDER BY avg_age_days DESC;
-- status: 1 New, 2 assigned, 3 planned, 4 PendingВозраст — не то же самое, что застой
Заявка, открытая 40 дней назад, но с задачей, зарегистрированной вчера, сильно отличается от заявки, открытой 40 дней назад, к которой никто не прикасался. Возраст (с момента создания) измеряет давность; застой (с момента последнего действия человека) измеряет заброшенность — и именно застой указывает на забытую заявку.
В сопровождении ошибкой, которая, как мы видели, обходится дорого, было использование date_mod в качестве «последнего действия». Столбец date_mod заявки обновляется чем угодно: отправленным уведомлением, добавленным наблюдателем, cron SLA, пересчитывающим срок, сработавшим бизнес-правилом. То есть он создаёт иллюзию движения в заявках, над которыми фактически никто не работал. Реальное последнее действие человека находится в комментариях и задачах — glpi_itilfollowups и glpi_tickettasks. Когда мы заменили date_mod на максимальную дату из этих двух таблиц, список застоявшихся заявок одного клиента вырос с 3 до 17: остальные 14 казались живыми только потому, что их каждый день задевала автоматизация.
-- Real staleness: days since the last human interaction
-- date_mod is unreliable (notifications, followers and cron bump it)
SELECT
t.id,
t.name,
DATEDIFF(NOW(), t.date) AS age_days,
DATEDIFF(NOW(), GREATEST(
t.date,
COALESCE(MAX(f.date), t.date),
COALESCE(MAX(k.date), t.date)
)) AS idle_days
FROM glpi_tickets t
LEFT JOIN glpi_itilfollowups f
ON f.itemtype = 'Ticket' AND f.items_id = t.id
LEFT JOIN glpi_tickettasks k
ON k.tickets_id = t.id
WHERE t.status NOT IN (4, 5, 6) -- exclude Pending, Solved, Closed
AND t.is_deleted = 0
GROUP BY t.id, t.name, t.date
HAVING idle_days >= 7
ORDER BY idle_days DESC;Распределение, а не только среднее
Прежде чем реагировать на выросшее среднее, посмотрите на форму очереди. Запрос ниже разбивает бэклог по диапазонам возраста и показывает длинный хвост, который среднее сглаживает:
-- Backlog distribution by age bracket
SELECT
CASE
WHEN DATEDIFF(NOW(), date) <= 3 THEN '0-3 days'
WHEN DATEDIFF(NOW(), date) <= 7 THEN '3-7 days'
WHEN DATEDIFF(NOW(), date) <= 15 THEN '7-15 days'
WHEN DATEDIFF(NOW(), date) <= 30 THEN '15-30 days'
ELSE '30+ days'
END AS bracket,
COUNT(*) AS tickets
FROM glpi_tickets
WHERE status NOT IN (4, 5, 6)
AND is_deleted = 0
GROUP BY bracket
ORDER BY MIN(DATEDIFF(NOW(), date));В качестве честного ориентира по диапазонам (календарные дни, не рабочие): меньше 3 дней — здорово, от 3 до 7 дней — приемлемо, от 7 до 15 дней — тревожный сигнал, а свыше 15 дней требует разбора каждой заявки по отдельности. Это не универсальные цели — справедливое значение зависит от договора и типа работы.
От числа к действию: матрица решений
Высокий возраст — не проблема, а симптом с несколькими причинами. Решение — прочитать технический сигнал и классифицировать, прежде чем действовать:
| Технический сигнал | Классификация | Действие |
|---|---|---|
| status 1 (Новая) и возраст > 3 дней | Не отсортирована | Назначить ответственного/группу прямо сейчас |
idle_days высокий, без внешнего наблюдателя | Забыта | Переназначить и потребовать выполнения |
| status 4 (В ожидании) с просроченным ответом | Истёкшая блокировка | Напомнить третьей стороне или переоткрыть |
высокий возраст и низкий idle_days | Обоснованно (сложная) | Пересмотреть SLA / объём работ |
| высокий возраст и повторяющаяся категория | Кандидат в проблему | Создать Проблему / статью базы знаний |
Тихий случай, который стоит выделить: заявки, застрявшие в статусе Новая, потому что бизнес-правило назначения не совпало с категорией и так и не задало группу. Они стареют незаметно — пропадают из панелей по группам и появляются, только когда вы смотрите на средний возраст без фильтра по группе.
Автоматизация еженедельного разбора
Выполнять запрос вручную не масштабируется. Мы сохраняем запрос по застою в файл .sql и планируем его в системном cron, читая учётные данные из файла .cnf (chmod 600), чтобы никогда не оставлять пароль в командной строке. Результат — еженедельный CSV, который становится повесткой разбора бэклога:
# /etc/cron.d/glpi-idade -> every Monday 07:30, as www-data
# Builds the list of stale tickets (7+ days) for the backlog review
30 7 * * 1 www-data /usr/bin/mysql --defaults-file=/etc/glpi/kpi-ro.cnf glpi \
< /opt/glpi-kpi/estagnados.sql \
> /var/log/glpi-kpi/estagnados-$(date +\%Y-\%m-\%d).csv 2>&1Типичные ошибки на практике
- Смотреть только на среднее: оно сглаживает хвост. Всегда отслеживайте распределение и, по возможности, медиану.
- Смешивать В ожидании с остальными: статус 4 — это законное ожидание; сам по себе он поднимает среднее и вызывает ложную тревогу.
- Использовать
date_modкак последнее действие: его обновляют автоматизации. Используйте даты комментариев и задач. - Сравнивать организации с разными календарями:
DATEDIFFсчитает календарные дни; организации с разными графиками работы нельзя сравнивать напрямую. - Забывать
is_deleted = 0: корзина GLPI не исчезает из таблицы и искажает любое среднее.
Следующий шаг
Объедините средний возраст с другими KPI службы поддержки (Service Desk) и соберите всё на панели в Metabase или Grafana с фильтром по организации и группе. Так возраст перестаёт быть числом в конце месяца и становится оповещением, которое срабатывает, пока ещё можно действовать.
В NexTool возраст и застой бэклога входят в ежемесячный отчёт о сопровождении, который мы передаём клиентам, вместе со списком заявок, требующих восстановления. Если вам нужен такой контроль в вашем GLPI, познакомьтесь с нашей услугой поддержки и сопровождения.
Проверено командой NexTool Solutions.