termenv
termenv copied to clipboard
Timeouts with Docker TTY
Not sure if it is intended or not, but if you run a docker container with --tty
, many queries termenv does timeout.
Minimum reproducible:
// main.go
package main
import (
"fmt"
"github.com/muesli/termenv"
)
func main() {
fmt.Println("BG", termenv.BackgroundColor())
}
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o a .
docker run --rm --tty -v $PWD:/tmp alpine /tmp/a
I amended @caarlos0 's example above to write tracing output:
// main.go
package main
import (
"fmt"
"os"
"runtime/trace"
"github.com/muesli/termenv"
)
func main() {
f, err := os.OpenFile("/tmp/trace.out", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
panic(err)
}
defer f.Close()
trace.Start(f)
defer trace.Stop()
fmt.Println("BG", termenv.BackgroundColor())
}
// go.mod
module termenvtimeout
go 1.20
require github.com/muesli/termenv v0.15.1
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/sys v0.6.0 // indirect
)
Running with Docker (in this case, Colima v0.5.5 aarch64) shows the following:
$ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o a .
$ docker run --rm --tty -v $PWD:/tmp alpine time /tmp/a
^[]11;rgb:14a7/195f/1efb^G^[[116;1RBG #000000
real 0m 5.03s
user 0m 0.00s
sys 0m 0.00s
I'm attaching the resulting trace, but here's the syscall graph for reference:
It looks like the culprit is https://github.com/muesli/termenv/blob/master/termenv_unix.go#L142
I ran into a similar issue with treefmt
. When running under lefthook
, I observe consistent hangs of almost exactly 10s. Setting the CI=1
environment variable fixes the issue.
After some debugging, I was able to narrow it down to running through PTY.
// client.go
package main
import (
"os"
"github.com/muesli/termenv"
)
func main() {
termenv.NewOutput(os.Stdout)
termenv.ForegroundColor()
}
// main.go
package main
import (
"io"
"os"
"os/exec"
"github.com/creack/pty"
)
func main() {
command := exec.Command("./client")
p, err := pty.Start(command)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, p)
_ = command.Wait()
}
When running, I see a 5s hang:
> gob client.go && time gor main.go
^[]10;rgb:bfbf/bdbd/b6b6^[\^[[68;1Rgo run main.go 0,36s user 0,21s system 10% cpu 5,179 total
I also see garbage output (what looks like escape sequences) on stdout and on the next prompt.