В показанном фрагменте ошибка flush игнорируется, а подтверждение cookies после Process требует идемпотентности. При частичном commit повтор может заново обработать уже выполненную часть.
func Pipe(p Producer, c Consumer) error {
В показанном фрагменте ошибка flush игнорируется, а подтверждение cookies после Process требует идемпотентности. При частичном commit повтор может заново обработать уже выполненную часть.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
func Pipe(p Producer, c Consumer) error { // TODO buf := make([]any, 0, MaxItems)
cookies := make([]int, 0)
flush := func() error { if len(buf) == 0 { return nil }
if err := c.Process(buf); err != nil {
return err
}
for _, cookie := range cookies {
if err := p.Commit(cookie); err != nil {
return err
}
}
buf = buf[:0]
cookies = cookies[:0]
return nil
}
for { items, cookie, err := p.Next()
if err != nil {
flush()
return err
}
Ответ
В показанном фрагменте ошибка flush игнорируется, а подтверждение cookies после Process требует идемпотентности. При частичном commit повтор может заново обработать уже выполненную часть.
Минимальное исправление ветки завершения:
if err != nil {
if flushErr := flush(); flushErr != nil { return flushErr }
if errors.Is(err, io.EOF) { return nil }
return err
}
Нужно отдельно определить контракт Next: может ли он вернуть данные вместе с ошибкой, сколько items относится к cookie и что означает Commit. Подтверждать cookie можно только после успешной обработки всех его элементов. Если Process сохраняет ссылку на buf, повторное использование массива через buf[:0] также опасно. Без интерфейсов Producer/Consumer полный алгоритм нельзя достоверно восстановить.