Реализуйте планировщик Scheduler, который выполняет зарегистрированные задачи
периодически — каждую со своим интервалом. Сами задачи исполняются на общем
пуле из workers воркеров, чтобы не плодить горутину на каждый запуск.
type Scheduler struct {
// ...
}
// NewScheduler создаёт планировщик с пулом из workers воркеров.
func NewScheduler(workers int) *Scheduler
// Add регистрирует задачу job, которую нужно запускать каждые interval.
func (s *Scheduler) Add(interval time.Duration, job func())
// Start запускает планировщик: тикеры и воркеры.
func (s *Scheduler) Start()
// Stop корректно останавливает планировщик: тикеры и воркеры завершаются.
func (s *Scheduler) Stop()
Каждая задача отправляется в общий канал по своему тикеру; воркеры разбирают
канал и выполняют задачи. Stop должен чисто остановить все тикеры и воркеров —
без утечек горутин и паник.
На что смотрит интервьюер:
- Периодичность: задача с интервалом
interval запускается примерно раз в
interval (тикер на задачу), задачи диспетчеризуются на общий пул.
- Воркер-пул: фиксированное число воркеров, разбирающих общий канал задач,
вместо горутины на каждый запуск.
- Чистая остановка:
Stop останавливает тикеры и завершает воркеров без
утечек горутин (проверяется через стабилизацию runtime.NumGoroutine).
- Отсутствие гонок и паник: запуск/останов под
-race, отправка в канал не
паникует при закрытии (корректный порядок завершения).
- Идемпотентность завершения: после
Stop задачи больше не запускаются.