Реализуйте воркер-пул Pool, который читает задачи Job из входного канала и
выполняет их в нескольких воркерах. Главное требование — корректное завершение с
ограничением по времени: Stop прекращает приём новых задач, даёт уже
запущенным задачам время timeout доделаться, а ID тех задач, которые не
успели завершиться за это время, возвращает вызывающему.
type Job struct {
ID int
Run func()
}
type Pool struct {
// ...
}
// NewPool создаёт пул из workers воркеров, читающих задачи из tasks.
func NewPool(workers int, tasks <-chan Job) *Pool
// Start запускает воркеров.
func (p *Pool) Start()
// Stop прекращает приём новых задач, даёт текущим время timeout доделаться.
// Возвращает ID задач, НЕ успевших завершиться за timeout.
func (p *Pool) Stop(timeout time.Duration) []int
Быстрые задачи (короче timeout) должны успеть завершиться. Медленные задачи
(дольше timeout), которые в момент истечения таймаута всё ещё выполняются,
должны попасть в возвращаемый срез ID.
На что смотрит интервьюер:
- Graceful shutdown:
Stop перестаёт принимать новые задачи и ждёт
выполняющиеся, но не дольше timeout.
- Учёт «зависших» задач: отслеживание множества выполняющихся в данный момент
ID через мьютекс/защищённую структуру; по таймауту — те, кто ещё «в полёте».
- Отсутствие гонок данных: множество in-flight ID читается и пишется из
разных горутин, доступ потокобезопасен (проверяется под
-race).
- Отсутствие утечек и дедлоков:
Stop всегда возвращается за разумное время,
даже если медленная задача ещё крутится.
- Корректность результата: быстрые задачи отработали, в срезе — ровно ID
медленных задач.