Application deadlock when initial model's init panics
eolso opened this issue · comments
Describe the bug
With the current flow in *Program.Run()
, the renderer isn't started until after the initial model has its .Init()
function called. This currently causes an issue in the event that the initial model panics unexpectedly because the program is set to recover from panics, but can't finish shutting down because it's in a deadlock. I propose moving the p.renderer.start()
to before the p.initialModel.Init()
call in order to prevent this deadlock scenario. This will at least have the renderer start listening for a done signal on the context in the event of a panic.
I'm unsure if there are other unintended side effects from this change, but I don't see any from testing all of the examples.
To Reproduce
Running the code in the Source Code
section will reproduce the issue. Instead of the expected panic being bubbled up, the app instead gets permanently stuck hanging waiting for
// Stop the renderer before acquiring the mutex to avoid a deadlock.
r.once.Do(func() {
r.done <- struct{}{}
})
to execute.
Source Code
package main
import tea "github.com/charmbracelet/bubbletea"
type model struct {
}
func (m model) Init() tea.Cmd {
//TODO implement me
panic("implement me")
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
//TODO implement me
panic("implement me")
}
func (m model) View() string {
//TODO implement me
panic("implement me")
}
func main() {
m := model{}
if _, err := tea.NewProgram(m).Run(); err != nil {
panic(err)
}
}
Expected behavior
Caught panic:
implement me
Restoring terminal...
Additional context
I have a fork with a branch created with the proposed change here.
Thanks for this; I can totally reproduce. Want to open a PR with your fork and then we can go from there?