Проблема
МенеджерФоновыхЗаданий хранит все запущенные задания в ConcurrentDictionary<int, BackgroundTask> _tasks (src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs). Записи удаляются из коллекции только:
- явным вызовом
Очистить();
- после успешного
ОжидатьЗавершенияЗадач() (и то только если ни одно задание не упало — иначе выбрасывается исключение и коллекция не чистится);
- при
Dispose() менеджера.
В долгоживущих процессах (веб-серверы, демоны, воркеры очередей и т.п.), которые запускают фоновые задания постоянно и ждут их через ОжидатьВсе/ОжидатьЛюбое или не ждут вовсе, коллекция растёт бесконечно. Каждое ФоновоеЗадание держит ссылки на объект-цель, массив параметров, результат и ИнформацияОбОшибке — это фактически утечка памяти, а ПолучитьФоновыеЗадания() со временем начинает возвращать огромный массив.
Предложение
Сделать коллекцию фоновых заданий самоочищающейся по принципу LRU-кеша с ограниченной ёмкостью: при превышении лимита вытеснять самые старые завершённые задания (Завершено, ЗавершеноАварийно, Отменено). Выполняющиеся задания вытесняться не должны — иначе сломаются ПолучитьТекущее() и ОжидатьЗавершенияЗадач().
Мотивация
Так же устроена «большая» платформа 1С:Предприятие: кластер серверов не хранит историю фоновых заданий бесконечно, а держит только последние ~1000 запущенных ФЗ; более старые завершённые задания просто перестают возвращаться через ФоновыеЗадания.ПолучитьФоновыеЗадания(). Прикладной код на это поведение уже рассчитан, так что аналогичное ограничение в OneScript не ломает ожидания разработчиков, пришедших из 1С, и убирает неконтролируемый рост памяти.
Детали для обсуждения
- Ёмкость по умолчанию — 1000, по аналогии с платформой. Возможно, стоит дать возможность её переопределить (параметр конструктора менеджера или настройка в
oscript.cfg).
- Задания, на которые у скрипта есть ссылки (например, лежат в массиве для
ОжидатьВсе), продолжают работать как обычные объекты — вытеснение касается только внутреннего реестра менеджера.
Очистить() и текущая очистка в ОжидатьЗавершенияЗадач() остаются как есть.
Проблема
МенеджерФоновыхЗаданийхранит все запущенные задания вConcurrentDictionary<int, BackgroundTask> _tasks(src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs). Записи удаляются из коллекции только:Очистить();ОжидатьЗавершенияЗадач()(и то только если ни одно задание не упало — иначе выбрасывается исключение и коллекция не чистится);Dispose()менеджера.В долгоживущих процессах (веб-серверы, демоны, воркеры очередей и т.п.), которые запускают фоновые задания постоянно и ждут их через
ОжидатьВсе/ОжидатьЛюбоеили не ждут вовсе, коллекция растёт бесконечно. КаждоеФоновоеЗаданиедержит ссылки на объект-цель, массив параметров, результат иИнформацияОбОшибке— это фактически утечка памяти, аПолучитьФоновыеЗадания()со временем начинает возвращать огромный массив.Предложение
Сделать коллекцию фоновых заданий самоочищающейся по принципу LRU-кеша с ограниченной ёмкостью: при превышении лимита вытеснять самые старые завершённые задания (
Завершено,ЗавершеноАварийно,Отменено). Выполняющиеся задания вытесняться не должны — иначе сломаютсяПолучитьТекущее()иОжидатьЗавершенияЗадач().Мотивация
Так же устроена «большая» платформа 1С:Предприятие: кластер серверов не хранит историю фоновых заданий бесконечно, а держит только последние ~1000 запущенных ФЗ; более старые завершённые задания просто перестают возвращаться через
ФоновыеЗадания.ПолучитьФоновыеЗадания(). Прикладной код на это поведение уже рассчитан, так что аналогичное ограничение в OneScript не ломает ожидания разработчиков, пришедших из 1С, и убирает неконтролируемый рост памяти.Детали для обсуждения
oscript.cfg).ОжидатьВсе), продолжают работать как обычные объекты — вытеснение касается только внутреннего реестра менеджера.Очистить()и текущая очистка вОжидатьЗавершенияЗадач()остаются как есть.