Files
larksuite-cli/shortcuts/mail
chenhuang c16a021ac6 fix(mail): replace os.Exit with graceful shutdown in mail watch (#350)
* fix(mail): replace os.Exit with graceful shutdown in mail watch

The signal handler in mail +watch called os.Exit(0), which bypassed all
deferred cleanup functions, made the code path untestable, and did not
follow Go's idiomatic context cancellation pattern.

Key changes:
- Remove os.Exit(0) and use context.WithCancel to propagate shutdown
- Run cli.Start in a separate goroutine so the main goroutine can return
  immediately on signal receipt (the Lark WebSocket SDK does not return
  promptly after context cancellation)
- Extract handleMailWatchSignal as a testable standalone function
- Use sync.Once + defer for idempotent cleanup on all exit paths
- Fix eventCount data race with atomic.Int64
- Add signal.Reset to support forced termination via a second Ctrl+C

Closes #268

* docs: add docstrings to handleMailWatchSignal test functions

* fix(mail): cancel watch context on signal handler panic

If handleMailWatchSignal panics, the recover block now calls
cancelWatch() to unblock the main select. Without this, a panic
would leave shutdownBySignal unclosed and watchCtx uncancelled,
causing the process to hang.

* fix(mail): use triggerShutdown to unblock main select on signal handler panic

The previous panic recovery only called cancelWatch(), but since the
WebSocket SDK does not return promptly after context cancellation,
the main select could still hang waiting on startErrCh.

Introduce triggerShutdown() that closes shutdownBySignal (via
sync.Once) and cancels the watch context, used by both the normal
signal path and the panic recovery path. This ensures the main
select unblocks immediately regardless of how the signal goroutine
exits.

Add regression test that forces a panic and asserts shutdownBySignal
is closed promptly.
2026-04-09 21:57:02 +08:00
..