Я передаю вывод команды клиенту с этим кодом. Команда построена с отменой контекста. Клиент отправляет запрос «отмена» на сервер, который уведомляет cancelCh
клиента, который запускает cancel()
.
Проблема, с которой я сталкиваюсь, заключается в том, что когда команда отменяется, остальные выходные команды выводятся в поток. клиенту, как будто команда не была отменена. После того, как команда выполнена, exit status 1
получено; который показывает, что команда действительно была отменена.
Если я переместлю канал done
в блок после cmd.Wait()
вместо того, чтобы раньше, я получу поведение, которое ожидаю. Клиент сразу получает exit status 1
и данные больше не отправляются. Но это, кажется, вызывает проблему гонки данных: https://github.com/golang/go/issues/19685. Эта проблема устарела, но я думаю, что она актуальна.
Как правильно передавать потоковые данные клиенту в режиме реального времени, а также сразу же завершать работу через отмену контекста?
go func() {
defer func() {
cancel()
}()
<-client.cancelCh
}()
output := make(chan []byte)
go execute(cmd, output)
for data := range output {
fmt.Fprintf(w, "data: %s\n\n", data)
flusher.Flush()
}
func execute(cmd *exec.Cmd, output chan []byte) {
defer close(output)
cmdReader, err := cmd.StdoutPipe()
if err != nil {
output <- []byte(fmt.Sprintf("Error getting stdout pipe: %v", err))
return
}
cmd.Stderr = cmd.Stdout
scanner := bufio.NewScanner(cmdReader)
done := make(chan struct{})
go func() {
for scanner.Scan() {
output <- scanner.Bytes()
}
done <- struct{}{}
}()
err = cmd.Start()
if err != nil {
output <- []byte(fmt.Sprintf("Error executing: %v", err))
return
}
<-done
err = cmd.Wait()
if err != nil {
output <- []byte(err.Error())
}
//<-done
}