Реализуйте ProcessOrders: она обрабатывает заказы пулом из w воркеров, то есть не больше w вызовов process одновременно. Функция process(id) может вернуть ошибку.
func ProcessOrders(orderIDs []int, w int, process func(id int) error) error
Пример:
err := ProcessOrders([]int{1, 2, 3, 4, 5, 6}, 2, func(id int) error {
if id == 3 {
return errors.New("заказ 3 невалиден")
}
return nil
})
// err: "заказ 3 невалиден"; заказы 4, 5, 6 могут не обработаться
Требования:
- Одновременно выполняется не больше
w вызовов process.
- После первой ошибки пул перестаёт раздавать новые заказы, а функция возвращает именно эту ошибку. «Первая» значит первая, которую успел записать какой-то воркер.
- Если все заказы обработаны без ошибок, возвращается
nil.
- Функция возвращается только после завершения всех воркеров, лишних горутин не остаётся.
w < 1 считается как w = 1.
- Используйте
context и каналы, без golang.org/x/sync.
Отмена касается раздачи новых заказов. Уже запущенный process прервать нельзя, так как он не принимает контекст: функция дожидается его завершения. Из-за случайного выбора в select воркер, который уже ждёт, иногда успевает взять ещё один заказ после отмены. Жёсткая гарантия «после ошибки ни одного нового вызова» не требуется.
Тесты проверяют: 500 заказов обработаны, максимальный параллелизм не больше w; на 1000 заказах с ошибкой в заказе 42 возвращается эта ошибка, а обработаны не все. Дополнительно: к моменту возврата ни один process не выполняется и лишних горутин нет (в том числе после ошибки при медленных соседних вызовах), w = 0 и отрицательные w работают как один воркер, пустой список даёт nil.