Реализуйте конвейер из трёх стадий: Reader, Parser, Validator. У каждой стадии свой пул горутин, между стадиями каналы. На вход идут сырые строки, на выходе срез валидных записей.
// Тип LogRecord уже объявлен в окружении задачи.
type LogRecord struct {
Level string
Msg string
}
func RunPipeline(lines []string, readers, parsers, validators int) []LogRecord
Формат строки: "LEVEL|message", разделитель |.
- Reader передаёт строки дальше без изменений. Это учебная стадия: на ней отрабатывается схема «пул плюс закрытие канала», как и на остальных.
- Parser делит строку по первому
| на Level и Msg. Если разделителя нет, Level получает всю строку, а Msg пустое.
- Validator отбрасывает записи с пустым
Level и с Level не из набора INFO, WARN, ERROR.
Пример:
lines := []string{"INFO|started", "DEBUG|trace", "|no level", "ERROR|crash"}
RunPipeline(lines, 2, 4, 2)
// [{INFO started} {ERROR crash}] — порядок может быть любым
Требования:
- На каждой стадии работает столько горутин, сколько указано в параметре. Значение меньше 1 считается равным 1.
- Порядок результата не определён, проверяется только набор записей.
- Каждый межстадийный канал закрывается ровно один раз, после того как все горутины предыдущей стадии закончили писать в него.
- После возврата функции не должно остаться работающих горутин. Нет гонок под
-race.
Тесты сверяют набор записей на 8 строках (5 валидных, 3 нет), разбор по первому | (INFO|a|b даёт Msg = "a|b", строка ERROR без разделителя даёт запись {ERROR ""}), точное совпадение регистра уровня, 400 строк с повторами при разных размерах пулов (включая значения меньше 1), пустой вход и отсутствие лишних горутин после возврата. Сколько именно горутин работает на каждой стадии, тесты не проверяют.