'PipWriter.Write does not write into stream. Return value was 0

Use case (trimmed and converted for public share)

We are trying to run a long-running process and want to stream the output to the caller function.

 func (c *Command) GetResultStream(config *Config, outputWriter *io.PipeWriter, errorWriter *io.PipeWriter) (*Result, bool) {
    log.Printf("Executing the command %q with config %q", c.String(), config.String())
    cmd := exec.Command(c.Command, c.Arguments...)

    if config.RedirectErrorStream {
        return &Result{
            ExitCode: ExitCodeInvalidInputConfiguration,
            Output:   "",
            Errors:   []string{"Cannot enable RedirectErrorStream configuration for Streaming output"},
        }, false
    }

    outputReader, err := cmd.StdoutPipe()
    defer common.CloseQuitely(outputReader)
    if err != nil {
        log.Printf("Error occurred while getting the output stream for the command %q. Error is %v", c.String(), err)
        return &Result{
            ExitCode: ExitCodeUnableToGetStdOutStream,
            Output:   "",
            Errors:   []string{err.Error()},
        }, false
    }
    errorReader, err := cmd.StderrPipe()
    defer common.CloseQuitely(errorReader)
    if err != nil {
        log.Printf("Error occurred while getting the error stream for the command %q. Error is %v", c.String(), err)
        return &Result{
            ExitCode: ExitCodeUnableToGetStdErrStream,
            Output:   "",
            Errors:   []string{err.Error()},
        }, false
    }

    err = cmd.Start()
    if err != nil {
        log.Printf("Error occurred while starting the cmmand %q. Error is %v", c.String(), err)
        return &Result{
            ExitCode: ExitCodeFailedToStartCommand,
            Output:   "",
            Errors:   []string{err.Error()},
        }, false
    }

    var waitGroup sync.WaitGroup
    waitGroup.Add(2)
    go func() {
        defer waitGroup.Done()
        scanner := bufio.NewScanner(outputReader)
        for scanner.Scan() {
            line := scanner.Text()
            _, err := outputWriter.Write([]byte(line))
            if err != nil {
                log.Printf("Error occurred while writing to output writer. Error is %v", err)
            }
        }
    }()

    go func() {
        defer waitGroup.Done()
        scanner := bufio.NewScanner(errorReader)
        for scanner.Scan() {
            line := scanner.Text()
            _, err := errorWriter.Write([]byte(line))
            if err != nil {
                log.Printf("Error occurred while writing to error writer. Error is %v", err)
            }
        }
    }()

    err = cmd.Wait()
    if err != nil {
        log.Printf("Error occurred while waiting for the command %q to finish. Error is %v ", c.String(), err)
        exitCode := ExitCodeSuccess
        if exitError, ok := err.(*exec.ExitError); ok {
            exitCode = exitError.ExitCode()
        }
        return &Result{
            ExitCode: exitCode,
            Output:   "",
            Errors:   []string{err.Error()},
        }, false
    }

    waitGroup.Wait()

    return &Result{
        ExitCode: 0,
        Output:   "",
        Errors:   nil,
    }, true

}

Caller code

cmd := command.NewCommand("tail", "-f", "/private/tmp/test.txt")

outputReader, outputWriter := io.Pipe()

errorReader, errorWriter := io.Pipe()
defer common.CloseQuitely(errorReader)
defer common.CloseQuitely(errorWriter)

var waitGroup sync.WaitGroup
waitGroup.Add(1)
go func() {
    defer waitGroup.Done()
    scanner := bufio.NewScanner(outputReader)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Print(line)
    }
}()

res, ok := cmd.GetResultStream(command.DefaultConfig, outputWriter, errorWriter)

if !ok {
    log.Fatalf("Failed to run the command %q. Error is %v", cmd.String(), res.Errors)
    return
}

waitGroup.Wait()

We are getting data into go routine in the GetResultStream method and we are calling outputWriter.Write method but it is not getting written and thus not returned to the caller. On debugging Write method returns 0 bytes wrote.

go


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source