From dce1f7dacded8f84aa4f8bf13a1bdabac00ce968 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Sun, 20 Sep 2026 11:54:20 +0200 Subject: [PATCH] Ignore SIGHUP instead of shutting down the server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream report (cloudreve/cloudreve#3586) reads as a crash: the server dies two minutes after launch. The attached log shows a clean signal-driven shutdown — SIGHUP was registered in signal.Notify, and the reporter's terminal/SSH session closing sent SIGHUP to the process. For a long-running server this is the wrong semantics: a terminal hangup should not stop the service. SIGHUP's default disposition is terminate, so it must be explicitly ignored rather than merely removed from Notify. Verified live: server survives kill -HUP (HTTP stays responsive) and still shuts down gracefully on SIGTERM/SIGINT/SIGQUIT. Fixes #200. Authored By: TDvorak Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- ROADMAP.md | 2 +- cmd/server.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0a6cbd22..0d128c39 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -207,7 +207,7 @@ Order = user-visible value first; each ships with backend + UI + tests. - #3454 (PG FK on upload) is **Pro-only** — `audit_logs` doesn't exist in this codebase. When B.5 adds our own audit log: insert the audit row in the same tx *after* the file row, never before. - [ ] #199 (upstream #3584) — markdown editor lag: profile the MDX editor path; likely re-render-per-keystroke, evaluate debounce/virtualization or lighter editor before swapping libraries - [x] #198 (upstream #3581) — "import files" task shows source storage policy "unknown": `ImportTaskState.PolicyName` baked at creation (resolved best-effort via `StoragePolicyClient`), summary emits `dst_policy_name` so admin views of other users' tasks work without a policy lookup; `policyOptionCache` retyped to `StoragePolicyBrief[]` and populated from `getAllowedPolicies()` at session init as fallback for legacy tasks -- [ ] #200 (upstream #3586) — Pro crash on SIGHUP; log shows a clean signal-driven shutdown, no stack trace — watch for a CE repro, likely not actionable yet +- [x] #200 (upstream #3586) — SIGHUP "crash": the upstream log was a clean signal-driven shutdown (SIGHUP was registered in `signal.Notify`), triggered when the reporter's terminal/SSH session closed. `signal.Ignore(syscall.SIGHUP)` now — default disposition would terminate the process; verified live: server survives `kill -HUP` (HTTP stays 200) and still shuts down cleanly on SIGTERM - [x] `desloppify` pass — 73 review items dispositioned (46 fixed, 27 honestly skipped), strict score 77.1 (was 18.9); scorecard lives in README. `security-reviewer` pass done incrementally per batch (OAuth secrets, SSRF, process exec, path safety) - [x] Tag management page (upstream #2962) — owner-scoped `tag:` metadata stats/rename/recolor/delete in `inventory.FileClient`, `GET/PATCH/DELETE /file/tag` routes, Settings → Tags tab with merge-on-rename semantics - [x] Download URL shuffling (#173) — `download_cdn_shuffle` distributes generated download URLs randomly across the site URL + `download_cdn_routes` endpoints (`setting.DownloadURLBase`, honors `UseFirstSiteUrl`); covers entity downloads, archive sessions, and redirect-type direct links; manual route picker hidden client-side while active diff --git a/cmd/server.go b/cmd/server.go index 08b51178..44636236 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -31,9 +31,13 @@ var serverCmd = &cobra.Command{ server.PrintBanner() - // Graceful shutdown after received signal. + // Graceful shutdown after received signal. SIGHUP (terminal hangup) + // is explicitly ignored: its default disposition terminates the + // process, which kills servers accidentally left running in an SSH + // session. Use SIGINT/SIGTERM/SIGQUIT to stop the server. sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) + signal.Ignore(syscall.SIGHUP) + signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) go shutdown(sigChan, logger, server) if err := server.Start(); err != nil {