Let recorder worker close encoder stdin
This commit is contained in:
committed by
Brandon McGinty
parent
d07d7342da
commit
e309d22137
@@ -108,7 +108,7 @@ Priority 1: transport, lifecycle, and correctness
|
|||||||
context, stop channel, output channel, and WaitGroup. Stop must cancel and
|
context, stop channel, output channel, and WaitGroup. Stop must cancel and
|
||||||
join that session before another begins.
|
join that session before another begins.
|
||||||
|
|
||||||
13. Recorder Stop races the encoder writer
|
[x] 13. Recorder Stop races the encoder writer
|
||||||
File: recording/recorder.go
|
File: recording/recorder.go
|
||||||
Stop closes stdin while run may be writing. A normal stop can therefore
|
Stop closes stdin while run may be writing. A normal stop can therefore
|
||||||
record a closed-pipe error and be reported as failed. Have run own stdin
|
record a closed-pipe error and be reported as failed. Have run own stdin
|
||||||
|
|||||||
@@ -128,10 +128,9 @@ func (r *Recorder) Stop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
r.once.Do(func() {
|
r.once.Do(func() {
|
||||||
|
// run owns stdin and closes it only after it has stopped writing.
|
||||||
|
// Closing it here races writePCM and turns a normal stop into EPIPE.
|
||||||
close(r.stop)
|
close(r.stop)
|
||||||
if r.stdin != nil {
|
|
||||||
r.stdin.Close()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
select {
|
select {
|
||||||
case <-r.done:
|
case <-r.done:
|
||||||
|
|||||||
@@ -1,12 +1,35 @@
|
|||||||
package recording
|
package recording
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type trackingWriteCloser struct{ closed bool }
|
||||||
|
|
||||||
|
func (w *trackingWriteCloser) Write([]byte) (int, error) { return 0, nil }
|
||||||
|
func (w *trackingWriteCloser) Close() error { w.closed = true; return nil }
|
||||||
|
|
||||||
|
var _ io.WriteCloser = (*trackingWriteCloser)(nil)
|
||||||
|
|
||||||
|
// Regression: Stop closed ffmpeg stdin while the worker could still write,
|
||||||
|
// creating a spurious closed-pipe recording failure.
|
||||||
|
func TestStopLeavesEncoderClosureToWorker(t *testing.T) {
|
||||||
|
stdin := &trackingWriteCloser{}
|
||||||
|
done := make(chan struct{})
|
||||||
|
close(done)
|
||||||
|
r := &Recorder{stdin: stdin, stop: make(chan struct{}), done: done}
|
||||||
|
if err := r.Stop(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if stdin.closed {
|
||||||
|
t.Fatal("Stop closed stdin instead of the worker")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNormalizeFormat(t *testing.T) {
|
func TestNormalizeFormat(t *testing.T) {
|
||||||
tests := map[string]string{
|
tests := map[string]string{
|
||||||
"": "flac",
|
"": "flac",
|
||||||
|
|||||||
Reference in New Issue
Block a user