fix: check health endpoint instead of awaiting service restart to fix update success status

This commit is contained in:
UndefinedPony
2024-12-31 11:20:59 +01:00
parent 2be79304fb
commit 187f051484
2 changed files with 71 additions and 30 deletions

View File

@@ -11,30 +11,50 @@ import {
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { api } from "@/utils/api";
import { HardDriveDownload } from "lucide-react";
import { HardDriveDownload, Loader2 } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
interface Props {
isNavbar?: boolean;
}
export const UpdateWebServer = () => {
const [updating, setUpdating] = useState(false);
const [open, setOpen] = useState(false);
export const UpdateWebServer = ({ isNavbar }: Props) => {
const { mutateAsync: updateServer, isLoading } =
api.settings.updateServer.useMutation();
const { mutateAsync: updateServer } = api.settings.updateServer.useMutation();
const buttonLabel = isNavbar ? "Update available" : "Update Server";
const handleConfirm = async () => {
const checkIsUpdateFinished = async () => {
try {
await updateServer();
const response = await fetch("/api/health");
if (!response.ok) {
throw new Error("Health check failed");
}
toast.success(
"The server has been updated. The page will be reloaded to reflect the changes...",
);
setTimeout(() => {
// Allow seeing the toast before reloading
window.location.reload();
}, 2000);
} catch {
// Delay each request
await new Promise((resolve) => setTimeout(resolve, 2000));
// Keep running until it returns 200
void checkIsUpdateFinished();
}
};
const handleConfirm = async () => {
try {
setUpdating(true);
await updateServer();
// Give some time for docker service restart before starting to check status
await new Promise((resolve) => setTimeout(resolve, 8000));
await checkIsUpdateFinished();
} catch (error) {
setUpdating(false);
console.error("Error updating server:", error);
toast.error(
"An error occurred while updating the server, please try again.",
@@ -43,35 +63,54 @@ export const UpdateWebServer = ({ isNavbar }: Props) => {
};
return (
<AlertDialog>
<AlertDialog open={open}>
<AlertDialogTrigger asChild>
<Button
className="relative w-full"
variant={isNavbar ? "outline" : "secondary"}
isLoading={isLoading}
variant="secondary"
onClick={() => setOpen(true)}
>
{!isLoading && <HardDriveDownload className="h-4 w-4" />}
{!isLoading && (
<span className="absolute -right-1 -top-2 flex h-3 w-3">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
<span className="relative inline-flex rounded-full h-3 w-3 bg-green-500" />
</span>
)}
{isLoading ? "Updating..." : buttonLabel}
<HardDriveDownload className="h-4 w-4" />
<span className="absolute -right-1 -top-2 flex h-3 w-3">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
<span className="relative inline-flex rounded-full h-3 w-3 bg-green-500" />
</span>
Update Server
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogTitle>
{updating
? "Server update in progress"
: "Are you absolutely sure?"}
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will update the web server to the
new version. The page will be reloaded once the update is finished.
{updating ? (
<span className="flex items-center gap-1">
<Loader2 className="animate-spin" />
The server is being updated, please wait...
</span>
) : (
<>
This action cannot be undone. This will update the web server to
the new version. You will not be able to use the panel during
the update process. The page will be reloaded once the update is
finished.
</>
)}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>Confirm</AlertDialogAction>
</AlertDialogFooter>
{!updating && (
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setOpen(false)}>
Cancel
</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>
Confirm
</AlertDialogAction>
</AlertDialogFooter>
)}
</AlertDialogContent>
</AlertDialog>
);

View File

@@ -359,7 +359,9 @@ export const settingsRouter = createTRPCRouter({
await pullLatestRelease();
await spawnAsync("docker", [
// This causes restart of dokploy, thus it will not finish executing properly, so don't await it
// Status after restart is checked via frontend /api/health endpoint
void spawnAsync("docker", [
"service",
"update",
"--force",