Skip to content

Interrupts while trying to read from stdin can cause the application to hang #60

@DanStough

Description

@DanStough

Describe the bug

Firstly, thanks for the great OSS project!

I'm building a CLI that reads from STDIN, and I'm trying to make sure it's cancelable using SIGINT. I observe that when I'm using Fang, there is a race condition when exiting that causes the application to hang indefinitely, maybe 50% of the time.

Setup

Please complete the following information along with version numbers, if applicable.

  • OS: MacOS 15.5
  • Shell: zsh
  • Terminal Emulator: ghostty
  • Terminal Multiplexer: n/a

To Reproduce

Steps to reproduce the behavior:

  1. Run the sample code below.
  2. Ctrl+C to close
  3. Observe that frequently the application doesn't close, or closes slowly.

Source Code

Here is a simplified example of my setup:

package main

import (
	"context"
	"io"
	"os"

	"github.com/charmbracelet/fang"
	"github.com/spf13/cobra"
)

func main() {
	// NewRootCMD creates the root command for the epok CLI application.
	rootCmd := &cobra.Command{
		Use:  "test",
		RunE: handler,
	}

	fang.Execute(context.Background(), rootCmd,
		fang.WithNotifySignal(os.Interrupt, os.Kill))
}

func handler(cmd *cobra.Command, _ []string) error {
	data := make(chan string)

	go func() {
		in := cmd.InOrStdin()
		_, _ = io.ReadAll(in) // Will block
	}()

	ctx := cmd.Context()
	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-data:
		return nil
	}
}

Expected behavior

I expect the application to consistently exit as it would w/o fang.

Additional context

I traced the problem to this line, which uses STDIN to determine the terminal background. I imagine there is contention reading from the same descriptor.

Assuming it's not user error, one solution that works for me is to pre-compute the styles in Execute before running the cobra command. If you think that's the right change, I'm happy to make a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions