Skip to content

Commit dc99a56

Browse files
GOATS-1308: Refactor GOATS shutdown process for improved reliability (#649)
* GOATS-1308: Refactor GOATS shutdown process for improved reliability * Add towncrier entry [skip ci]
1 parent ad0c14c commit dc99a56

3 files changed

Lines changed: 41 additions & 7 deletions

File tree

docs/changes/649.change.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Refactored the GOATS shutdown process for improved reliability.

src/goats_tom/api_views/system.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,25 @@ def shutdown(self, request):
2626
status=status.HTTP_503_SERVICE_UNAVAILABLE,
2727
)
2828

29-
pid = int(pid_file.read_text().strip())
29+
try:
30+
pid = int(pid_file.read_text().strip())
31+
except (FileNotFoundError, ValueError):
32+
return Response(
33+
{"error": "GOATS PID file is missing or corrupted."},
34+
status=status.HTTP_503_SERVICE_UNAVAILABLE,
35+
)
36+
37+
try:
38+
os.kill(pid, signal.SIGINT)
39+
except ProcessLookupError:
40+
return Response(
41+
{"error": "GOATS process is no longer running."},
42+
status=status.HTTP_503_SERVICE_UNAVAILABLE,
43+
)
44+
except PermissionError:
45+
return Response(
46+
{"error": "Insufficient permissions to shut down GOATS process."},
47+
status=status.HTTP_403_FORBIDDEN,
48+
)
3049

31-
os.kill(pid, signal.SIGINT)
3250
return Response({"status": "shutdown initiated"})

src/goats_tom/templates/tom_common/base.html

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,35 @@
120120

121121
document.getElementById("shutdownConfirmBtn").addEventListener("click", async () => {
122122
window.modal.hide();
123+
const shutdownScreen =
124+
'<div style="display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif">' +
125+
'<p style="font-size:1.5rem">GOATS has shut down. Goodbye!</p></div>';
123126
try {
124-
await fetch("/api/system/shutdown/", {
127+
const response = await fetch("/api/system/shutdown/", {
125128
method: "POST",
126129
headers: {
127130
"X-CSRFToken": document.body.dataset.csrfToken,
128131
"Content-Type": "application/json",
129132
},
130133
});
134+
if (response.ok) {
135+
document.body.innerHTML = shutdownScreen;
136+
} else {
137+
window.toast.show({
138+
update: "notification",
139+
unique_id: "shutdown-error",
140+
color: "danger",
141+
label: "Shutdown failed",
142+
message: "Could not shut down GOATS. Please try again.",
143+
autohide: true,
144+
});
145+
}
131146
} catch (_) {
132-
// Expected: server shuts down mid-response.
147+
// Network error: the server cut the connection mid-response,
148+
// which is the expected path when Django shuts down before
149+
// the response is fully delivered.
150+
document.body.innerHTML = shutdownScreen;
133151
}
134-
document.body.innerHTML =
135-
'<div style="display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif">' +
136-
'<p style="font-size:1.5rem">GOATS is shutting down...</p></div>';
137152
});
138153
});
139154
}

0 commit comments

Comments
 (0)