gracefulShutdown function
Future<void>
gracefulShutdown({
- int exitCode = 0,
- ExitReason reason = ExitReason.other,
- String? finalMessage,
Graceful shutdown: cleans up resources, runs hooks, flushes analytics, exits.
Implementation
Future<void> gracefulShutdown({
int exitCode = 0,
ExitReason reason = ExitReason.other,
String? finalMessage,
}) async {
if (_shutdownInProgress) return;
_shutdownInProgress = true;
// Resolve the session-end hook budget.
const sessionEndTimeoutMs = 1500;
// Failsafe: guarantee process exits even if cleanup hangs.
final failsafeBudget =
const Duration(milliseconds: 5000).inMilliseconds >
sessionEndTimeoutMs + 3500
? const Duration(milliseconds: 5000)
: Duration(milliseconds: sessionEndTimeoutMs + 3500);
_failsafeTimer = Timer(failsafeBudget, () {
_cleanupTerminalModes();
_printResumeHint();
_forceExit(exitCode);
});
// Exit alt screen and print resume hint first.
_cleanupTerminalModes();
_printResumeHint();
// Flush session data — most critical cleanup.
try {
await runCleanupFunctions().timeout(const Duration(seconds: 2));
} catch (_) {
// Silently handle timeout and other errors.
}
// Execute SessionEnd hooks.
try {
if (_sessionEndHooks != null) {
await _sessionEndHooks!(reason, timeoutMs: sessionEndTimeoutMs);
}
} catch (_) {
// Ignore exceptions (including AbortError on timeout).
}
// Flush analytics — capped at 500 ms.
try {
if (_analyticsShutdown != null) {
await _analyticsShutdown!().timeout(const Duration(milliseconds: 500));
}
} catch (_) {
// Ignore analytics shutdown errors.
}
if (finalMessage != null) {
try {
stderr.writeln(finalMessage);
} catch (_) {
// stderr may be closed.
}
}
_forceExit(exitCode);
}