attempt to detect unrecoverable notmuch state
All checks were successful
Generic zig build / build (push) Successful in 28s

This commit is contained in:
Emil Lerch 2025-11-15 10:51:39 -08:00
parent a1de4e72c5
commit 691288e134
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 49 additions and 1 deletions

View file

@ -5,6 +5,12 @@ const auth = @import("auth.zig");
const version = @import("build_options").git_revision; const version = @import("build_options").git_revision;
fn exitAfterDelay() void {
std.Thread.sleep(500 * std.time.ns_per_ms);
std.log.err("Notmuch search is in unrecoverable state: exiting", .{});
std.process.exit(1);
}
pub fn main() !u8 { pub fn main() !u8 {
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); defer _ = gpa.deinit();
@ -208,6 +214,13 @@ fn queryHandler(db: *root.NotmuchDb, req: *httpz.Request, res: *httpz.Response)
const query = std.Uri.percentDecodeInPlace(query_buf); const query = std.Uri.percentDecodeInPlace(query_buf);
var threads = db.search(query) catch |err| { var threads = db.search(query) catch |err| {
if (err == error.CouldNotSearchThreads) {
res.status = 503;
try res.json(.{ .@"error" = "CouldNotSearchThreads", .fatal = true }, .{});
const exit_thread = std.Thread.spawn(.{}, exitAfterDelay, .{}) catch @panic("could not spawn thread to kill process");
exit_thread.detach();
return;
}
res.status = 500; res.status = 500;
try res.json(.{ .@"error" = @errorName(err) }, .{}); try res.json(.{ .@"error" = @errorName(err) }, .{});
return; return;

View file

@ -48,6 +48,11 @@ button:disabled { background: #444; cursor: not-allowed; }
.login-box h2 { margin-bottom: 1rem; } .login-box h2 { margin-bottom: 1rem; }
.login-box input { width: 100%; padding: 0.5rem; margin-bottom: 1rem; border: 1px solid #444; border-radius: 4px; background: #2a2a2a; color: #e0e0e0; } .login-box input { width: 100%; padding: 0.5rem; margin-bottom: 1rem; border: 1px solid #444; border-radius: 4px; background: #2a2a2a; color: #e0e0e0; }
.login-box button { width: 100%; } .login-box button { width: 100%; }
.restart-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 3000; align-items: center; justify-content: center; }
.restart-overlay.visible { display: flex; }
.restart-box { background: #252525; border: 1px solid #444; border-radius: 8px; padding: 2rem; text-align: center; }
.restart-box h2 { margin-bottom: 1rem; color: #ff6b6b; }
.restart-box p { margin-bottom: 1rem; color: #999; }
</style> </style>
</head> </head>
<body> <body>
@ -107,6 +112,14 @@ button:disabled { background: #444; cursor: not-allowed; }
<button onclick="submitLogin()">Login</button> <button onclick="submitLogin()">Login</button>
</div> </div>
</div> </div>
<div id="restart-overlay" class="restart-overlay">
<div class="restart-box">
<h2>Server Restarting</h2>
<p>The server encountered a fatal error and is restarting...</p>
<p id="retry-countdown">Retrying in <span id="retry-seconds">5</span> seconds</p>
</div>
</div>
</div> </div>
<script> <script>
let currentQuery = 'tag:inbox'; let currentQuery = 'tag:inbox';
@ -130,10 +143,32 @@ async function api(endpoint) {
if (!retryRes.ok) throw new Error(`API error: ${retryRes.status}`); if (!retryRes.ok) throw new Error(`API error: ${retryRes.status}`);
return retryRes.json(); return retryRes.json();
} }
if (!res.ok) throw new Error(`API error: ${res.status}`); if (!res.ok) {
if (res.status === 503) {
const data = await res.json();
if (data.fatal) {
showRestartOverlay();
throw new Error('Fatal server error');
}
}
throw new Error(`API error: ${res.status}`);
}
return res.json(); return res.json();
} }
function showRestartOverlay() {
document.getElementById('restart-overlay').classList.add('visible');
let seconds = 5;
const countdown = setInterval(() => {
seconds--;
document.getElementById('retry-seconds').textContent = seconds;
if (seconds <= 0) {
clearInterval(countdown);
location.reload();
}
}, 1000);
}
async function checkAuthStatus() { async function checkAuthStatus() {
try { try {
await api('auth/status'); await api('auth/status');