Task #6123
openTask #6116: EPIC: Speed up the stats updater daemon (scripts/workflow/update_stats.sh)
Gather metrics for companies/partners/users with a bounded worker pool
80%
Description
Problem¶
The three metric commands iterate strictly serially:
-
InitialStatsGatheringCommand—for (metricTitle …) { for (company in companies) { … } } -
PartnersMetricsGatheringCommand—for (metricService …) { for (partner in partners) { … } } -
UsersMetricsGatheringCommand— same shape over users
Each inner iteration is a network-bound call chain, so the CPU is idle almost the whole time and the wall clock is the sum of every request.
Proposed change¶
Run the inner loop over a bounded pool (a fixed executor / coroutine Semaphore, size from config, default small — 4 to 8) so several companies are in flight at once.
Depends on the session-reuse task. Parallelising the current code would multiply login/logout churn and hit IIKO's session limit immediately; with one shared session the concurrency budget goes to actual report requests. Size the pool below IIKO's licensed concurrent-request limit and make it configurable so it can be tuned down if IIKO starts refusing.
Also set OkHttp's Dispatcher.maxRequestsPerHost on the shared client in NetworkRequestsService — it defaults to 5 and would otherwise silently cap the pool.
Per-item failures must stay isolated the way they are today (the existing try/catch … continue per company).
Acceptance¶
- Pool size configurable, default conservative.
- A failing company does not abort the run.
- Measured wall-clock improvement recorded on the issue.
Updated by Redmine Admin about 8 hours ago
- Blocked by Task #6117: Reuse one IIKO session per command run instead of login/logout per request added
Updated by Redmine Admin about 7 hours ago
- Status changed from New to Feedback
- % Done changed from 0 to 80
Механика реализована, ветка speedup/stats-daemon, коммит 50a6ebef. Оставляю в Feedback, а не в Resolved: по умолчанию параллелизм = 1, то есть поведение ровно прежнее. Задача закроется, когда кто-то поднимет значение на сервере и запишет сюда замер.
StatsGatheringExecutor (.../stats_gatherers/common/services/):
-
iiko.stats.parallelism, по умолчанию 1 — тот же последовательный обход, что и раньше; - при значении > 1 — фиксированный пул на
min(parallelism, items.size); - сбой на одном элементе логируется и не роняет остальные, как в исходных
try/catch … continue.
Подключён во всех трёх командах: InitialStatsGatheringCommand (по компаниям), PartnersMetricsGatheringCommand (по партнёрам), UsersMetricsGatheringCommand (по юзерам).
Почему по умолчанию 1. Поднимать параллелизм вслепую нельзя: лицензионный лимит одновременных подключений iiko здесь неизвестен, а проверить не на чем. Правильный порядок — сначала выкатить #6117 и #6118 (после них запросов к iiko становится на порядки меньше), потом поднимать iiko.stats.parallelism по шагам и смотреть, с какого значения iiko начинает отказывать.
Не сделано: Dispatcher.maxRequestsPerHost на общем OkHttp-клиенте в NetworkRequestsService остался дефолтным (5). Это потолок для пула — при parallelism > 5 его надо поднимать вместе с ним. Не трогал, потому что клиент общий на все внешние интеграции, а не только на iiko, и менять его без замеров смысла нет. Делать это надо в один заход с подбором parallelism.