Reputation: 5830
For a personal project, I'm spawning an external process which hosts a REST API. I only want to pass control back to the main thread once the external process has been initialized, which can be known by reading Stdout.
So I have created an io.Writer
implementation which closes a channel once a certain criteria has been met.
type channelIOWriter struct {
InitializedChannel chan bool
isInitialized bool
buffer string
}
func newChannelIOWriter() *channelIOWriter {
retVal := new(channelIOWriter)
retVal.InitializedChannel = make(chan bool)
return retVal
}
func (writer *channelIOWriter) Write(data []byte) (int, error) {
for _, b := range data {
if b == '\n' {
writer.buffer = *bytes.NewBuffer(make([]byte, 0))
continue
}
writer.buffer.WriteByte(b)
if strings.HasPrefix(writer.buffer.String(), "ChromeDriver was started successfully.") {
if !writer.isInitialized {
close(writer.InitializedChannel)
}
writer.isInitialized = true
}
}
return len(data), nil
}
Next, I have the main function which, in a seperate goroutine, spawns the external process.
A wait is performed on the channel that's suposed to be closed by the io.Writer
implementation.
func main() {
writer := newChannelIOWriter()
go func() {
cmd := exec.Command("chromedriver", "--port=9009")
cmd.Stdout = writer
cmd.Start()
}()
<-writer.InitializedChannel
fmt.Println("Control is passed back to the MAIN thread.")
}
According to the comments on the question, it seems to be better to use a context. Anyone who can explain on how to use that?
Upvotes: 1
Views: 228
Reputation: 302
I stripped out all unnecessary detail and demo how context with deadline works
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
type example struct {
cancel context.CancelFunc
}
func (e *example) Write(data []byte) (int, error) {
defer e.cancel()
return len(data), nil
}
func main() {
deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
writer := &example{
cancel: cancel,
}
go func() {
cmd := exec.Command("ls", ".")
cmd.Stdout = writer
_ = cmd.Start()
}()
<-ctx.Done()
fmt.Println("Control is passed back to the MAIN thread.", ctx.Err())
}
Upvotes: 2