Skip to content

GemCheck blocks 120s on a GUI dialog and exits silently for CLI invocations on Linux (--help/--version/--active-sessions unusable when gems are missing) #1543

Description

@simtel12

Summary

On Linux, when any bundled gem is missing, GemCheck.verify! blocks for a full 120 seconds on a GUI dialog and then exits 1 having printed nothing to the terminal. Every CLI-only invocation is affected, including --help and --version, because the gem check runs at lich.rbw:39 — long before the CLI dispatcher is even loaded at lich.rbw:133.

The net effect from a terminal is that Lich appears to hang for two minutes and then do nothing, with no indication of why.

Reproduce

On a Linux box with zenity installed (any desktop distro), using a Ruby that doesn't yet have Lich's gems — e.g. right after following the 4.0.3 → 4.0.5 bump from #1529 with a fresh rbenv install:

ruby ~/code/dragonrealms/lich-5/lich.rbw --active-sessions

It sits for 120 seconds, prints nothing, exits 1. --help and --version behave identically. Interrupting shows where it is:

^C/home/user/code/dragonrealms/lich-5/lib/gemcheck.rb:541:in 'Process.wait': Interrupt
        from lib/gemcheck.rb:541:in 'block in Lich::GemCheck.run_with_timeout'
        from .../timeout.rb:306:in 'Timeout.timeout'
        from lib/gemcheck.rb:541:in 'Lich::GemCheck.run_with_timeout'
        from lib/gemcheck.rb:514:in 'Lich::GemCheck.alert_linux'
        from lib/gemcheck.rb:295:in 'Lich::GemCheck.alert'
        from lib/gemcheck.rb:73:in 'Lich::GemCheck.verify!'
        from lich.rbw:39:in '<main>'

Cause

alert_linux (lib/gemcheck.rb:512-522) picks a GUI dialog whenever one is on PATH:

if cmd_available?('zenity')
  run_with_timeout(['zenity', '--info', '--title', TITLE, '--text', body], ALERT_TIMEOUT_SECONDS)
elsif cmd_available?('kdialog')
  ...
else
  warn "!!ALERT!! #{body}"      # <-- the branch that would actually be visible
end

run_with_timeout spawns it with out: File::NULL, err: File::NULL and waits up to ALERT_TIMEOUT_SECONDS (120). So:

  • The dialog may be on another workspace, behind other windows, or simply not rendering — the user launched from a terminal and isn't looking for one.
  • Nothing reaches the terminal, because the message only ever goes into the dialog and the child's output is discarded.
  • After 120s the child is TERMed and verify! exits 1, still silently.

The information isn't lost, just never surfaced: alert calls write_log before opening the dialog, so TEMP_DIR/lich5-missing-gems.log already has the details. And the message it was trying to show is the actually-useful UNIX_MESSAGE — "You're missing required Ruby gems! Please run 'bundle install' from your Lich5 folder."

Why it bites harder than it looks

lich.rbw:39 runs GemCheck.verify! before lib/main/argv_options.rb is required at line 133. So the blocking dialog fires ahead of every early-exit CLI command — --help, --version, --active-sessions, --session-info, --link-to-sge, --install, and the rest. A user whose gems are missing cannot even run lich.rbw --help to find out what to do, which is exactly when they would.

Suggested fix

Prefer the terminal when there is one. alert_linux already has a perfectly good warn branch; it just isn't reachable when a dialog binary exists. Something like:

def alert_linux(body)
  return warn("!!ALERT!! #{body}") if $stdout.isatty
  # ... existing zenity/kdialog/xmessage chain
end

$stdout.isatty is already the established idiom for this in the codebase — lib/main/argv_options.rb uses it for --link-to-sge, --unlink-from-sge, and friends.

Options, roughly in order of preference:

  1. Use the warn fallback whenever $stdout.isatty, so terminal launches get an instant readable error and desktop-launcher starts keep the dialog.
  2. Additionally, print the log path unconditionally before opening any dialog, so there is always a breadcrumb.
  3. Optionally drop ALERT_TIMEOUT_SECONDS for the non-interactive case — two minutes is a long time to block a startup path that has already decided to exit 1.

Happy to put up a PR for (1) plus (2) if that's the direction you'd want.

Environment

  • Linux, zenity present
  • Ruby 4.0.5 via rbenv (fresh install, gems not yet installed for it — bundle install resolves the underlying missing-gem condition and is the correct user action; this issue is about the two-minute silent block that hides that fact)

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