main_loop
Описание
[MIRROR] Main Loop implementation to control subprocesses and threads
Языки
- Ruby98,8%
- Dockerfile1,2%
MainLoop
MainLoop — Ruby-библиотека для управления субпроцессами и потоками с функциями:
- автоматический сбор дочерних процессов (reaping)
- корректное завершение (SIGTERM/SIGINT) процессов и потоков
- автоматический перезапуск по количеству повторов
- принудительное завершение по таймауту
- обработка завершения процессов и потоков
MainLoop is a Ruby library for managing subprocesses and threads with features:
- automatic child process reaping
- graceful shutdown (SIGTERM/SIGINT) for processes and threads
- automatic restart by retry count
- timeout-based force termination
- process/thread completion handling
Возможности / Features
- Потоко-безопасный канал обмена событиями (IO.pipe) / Thread-safe event bus (IO.pipe)
- Управление процессами через Kernel.fork / Process management via Kernel.fork
- Управление потоками через Thread.new / Thread management via Thread.new
- Обработка сигналов TERM/INT/CLD / SIGTERM/INT/CLD signal handling
- Автоматический сбор завершенных процессов / Automatic child process reaping
- Retry-логика для перезапуска / Retry logic for restarts
- Принудительное завершение по таймауту / Timeout-based force termination
Начало работы / Getting started
gem install main_loop
При установке через bundler добавьте следующую строку в :
If you'd rather install using bundler, add a line for it in your :
gem 'main_loop'
Затем выполните / Then run:
bundle install # для установки гема / gem installation
Корневой модуль / Root module
- это корневой модуль, который подключает все компоненты:
is the root module that requires all components:
Субмодули / Submodules:
— канал обмена событиями (IO.pipe)MainLoop::Bus— координация обработчиков и управление жизненным цикломMainLoop::Dispatcher— главный цикл обработки событий и сигналовMainLoop::Loop— абстрактный базовый классMainLoop::Handler— управление субпроцессамиMainLoop::ProcessHandler— управление потокамиMainLoop::ThreadHandler
Архитектура / Architecture
Жизненный цикл обработчика / Handler lifecycle
Способы определения логики
Библиотека поддерживает два основных подхода для описания работы процессов и потоков:
1. Блок (inline block)
Передайте блок кода непосредственно в конструктор обработчика ( или ). В этом блоке размещается основная логика. При завершении (по сигналу, ошибке или таймауту) блок прерывается; вы можете определить дополнительные действия, используя переданный объект обработчика.
2. Объект с интерфейсом run / on_term
Передайте экземпляр класса, который реализует два обязательных метода:
— содержит основную логику; дляrunметод не принимает аргументов, дляProcessHandlerполучает объект потока.ThreadHandler— вызывается при необходимости завершить процесс/поток; дляon_termпринимает PID, дляProcessHandler— объект потока. В этом методе следует инициировать корректное завершение (например, послать сигнал процессу или установить флаг остановки для потока).ThreadHandler
Оба подхода могут комбинироваться с параметрами (, и т.д.) и одинаково хорошо интегрируются с циклом .
Выбор зависит от удобства: для простых сценариев подойдёт блок, для сложной логики управления завершением — объект с явными методами.
Использование / Usage
Базовая настройка / Basic setup
Обработка процессов / Process handling
Простейший пример / Simplest example
С блоком кода / With code block
С объектом runnable / With runnable object
Обработка потоков / Thread handling
Поток с блоком / Thread with block
Поток с блоком и колбэком завершения / Thread with block and termination callback
Поток с объектом runnable / Thread with runnable object
Запуск цикла / Start loop
Обработка завершения / Termination handling
Когда отправляется сигнал или :
перехватывает сигнал и отправляетtrapbus.puts("sig:TERM")получает событие изLoopи вызываетBusDispatcher#termустанавливаетDispatcher@terminating_at = Time.now- Все обработчики получают
:termпосылаетProcessHandlerProcess.kill('TERM', pid)вызываетThreadHandlerблок@on_term
- Если через
(по умолчанию 5 сек) процессы не завершились:timeoutпроверяетDispatcher#tickneed_force_kill?- Если
— посылаетtrueвсем обработчикамkill
- Когда все обработчики завершаются (
):finished?вызываетDispatcher#try_exit!exit(@exit_code)
When sending or signal:
catches the signal and sendstrapbus.puts("sig:TERM")gets the event fromLoopand callsBusDispatcher#termsetsDispatcher@terminating_at = Time.now- All handlers receive
:termsendsProcessHandlerProcess.kill('TERM', pid)callsThreadHandlerblock@on_term
- If processes don't terminate within
(default 5 seconds):timeoutchecksDispatcher#tickneed_force_kill?- If
— sendstrueto all handlerskill
- When all handlers finish (
):finished?callsDispatcher#try_exit!exit(@exit_code)
Повторы (retry) / Retry
Публикация событий / Publishing events
Обработчики могут отправлять события в шину:
Handlers can publish events to the bus:
Особенности / Features
- Потоко-безопасность:
иBusиспользуютDispatcherMonitorMixin - Таймауты:
используется для timeout вTimeouterиBus#getsLoop#start_loop_forever - Логирование: все классы принимают параметр
, по умолчаниюlogger:Logger.new(nil) - Ошибки: используйте
(не пустойrescue StandardError)rescue - Коды выхода:
в процессах,exit!(code)в основном потокеexit(code)
- Thread safety:
andBususeDispatcherMonitorMixin - Timeouts:
is used for timeout inTimeouterиBus#getsLoop#start_loop_forever - Logging: all classes accept
parameter, default islogger:Logger.new(nil) - Error handling: use
(not barerescue StandardError)rescue - Exit codes:
in processes,exit!(code)in main threadexit(code)
Тестирование / Testing
Для запуска примеров из локальной копии репозитория (без установки гема) используйте опцию интерпретатора Ruby, указав путь к директории относительно текущей папки:
Версия / Version
Текущая версия / Current version:
Автор / Author
Юрий Самойленко / Yuri Samoylenko kinnalru@gmail.com
Лицензия / License
Библиотека доступна с открытым исходным кодом в соответствии с условиями лицензии MIT.
The gem is available as open source under the terms of the MIT License.