.. | ||
README.md | ||
scheduler.go | ||
scheduler_test.go |
scheduler
Пакет scheduler
реализует планировщик системы. scheduler.Scheduler
хранит полное состояние кластера
и принимает решение на каком воркере и какой джоб нужно запустить.
Шедулер является точкой координации между воркерами и билдами. Бегущие билды обращаются к шедулеру,
передавая джобы в функцию ScheduleJob
. Воркеры забирают джобы из шедулера вызывая функцию PickJob
.
После того, как воркер завершил выполнение джоба, он вызывает функцию OnJobComplete
. Эту функцию
могут вызвать даже для того джоба, который никто не шедулил. В этом случае планировщик просто должен
запомнить, что результаты джоба сохранены в кеше на воркере.
Фукнция LocateArtifact
должна возвращать имя любого воркера, который хранит в кеше заданный артефакт.
Эта функция не нужна в этой задаче, но он потребуется вам для реализации передачи артефактов между
воркерами.
Для того, чтобы зачесть домашнее задание, достаточно реализовать упрошённый алгоритм планирования с
одной глобальной очередью. Функция ScheduleJob
должна помещать job
в очередь, или возвращать ссылку на существующий
pendingJob
. Функция PickJob
должна извлекать первый элемент из очереди. Обратите внимание, что функция PickJob
принимает контекст. Поскольку это блокирующая операция, она должна поддерживать отмены. Если вы забудете
реазиловать отмену в этом месте, интеграционные тесты будут зависать.
Алгоритм планирования
Далее описывается продвинутый алгоритм планирования. Алгоритм проверяется в отдельной задаче smartsched
.
Для зачёта по домашнему заданию, реализовывать этот алгоритм не обязательно.
Планировщик поддерживает множество очередей:
- Одна глобальная очередь.
- По две локальные очереди на воркер.
При запросе нового джоба воркер выбирает случайную джобу из трех очередей - глобальной, и двух локальных относящихся
к этому воркеру. Случайная очередь выбирается одним вызовом select {}
.
Ожидающий исполнения джоб всегда находится в первой локальной очереди воркеров, на которых есть результаты работы этого джоба.
Если джоб ждёт выполнения дольше CacheTimeout
или если в момент SchedulerJob
джоба не было в кеше ни на одном
из воркеров, то он попадает во все вторые локальные очереди воркеров, на которых есть хотя бы один артефакт
из множества зависимостей этого джоба.
Определения первой и второй локальной очереди не зависят от того, в каком порядке в шедулер пришли джобы
и информация о кеше артефактов. То есть, если джоб уже находится в глобальной очереди, и в этот момент приходит
информация, что этот джоб находится в кеше на воркере W0
, то джоб должен быть добавлен
в первую локальную очередь W0
.
Если джоб ждёт выполнения дольше DepTimeout
, то он помещается в глобальную очередь.
Тестирование
Вместо реального времени, юниттесты шедулера используют библиотеку clockwork
. Это накладывает ограничения
на детали вашей реализации. Ожидание CacheTimeout
и DepTimeout
должно быть реализовано как select {}
на
канале, который вернула функция TimeAfter
. Мы считаем что CacheTimeout < DepTimeout
, и ожидание этих
таймаутов происходит последовательно в одной горутине.