Description
Describe the bug
A context cancellation while the program is inside the message processing part of the eventLoop deadlocks. It is trying to send a command into the cmds channel, which no longer has any receivers. This happens because at that point the handleCommands has already exited, having detected the cancelled context, and the eventLoop blocks indefinitely while trying to send into the stale commands channel.
May happen here:
Line 463 in 6a1ebaa
Definitely happens here:
Line 509 in 6a1ebaa
To Reproduce
Cancellation of a given tea.WithContext(ctx) inside a high message pressure implementation, e.g. with 1-second interval Tick commands.
Expected behavior
Program exit with appropriate and timely teardown on context cancellation.
Possible Hotfix
Wrapping the command channel sends with appropriate select statements resolves the issue. However, I'm not sure if generally more safeguards may need to be put in place in the event loop's message processing part. Some dependent routines may already be shutdown due to context cancellation and message handling inside the event loop may still call such functions if context cancellation isn't handled before that happens.
select {
case <-p.ctx.Done():
return model, nil
case cmds <- cmd:
}
Additional context (Stacktrace)
goroutine 42 [chan send, 4 minutes]:
github.com/charmbracelet/bubbletea.(*Program).eventLoop(0xc000264140, {0x673950?, 0xc0003b8008?}, 0xc0001ae230)
github.com/charmbracelet/[email protected]/tea.go:509 +0x7f7
github.com/charmbracelet/bubbletea.(*Program).Run(0xc000264140)
github.com/charmbracelet/[email protected]/tea.go:647 +0xabc