(feature) Add cancellable backup runs and clearer dry-run logs
Add a cancel action for queued and running backup runs. Queued runs are cancelled immediately, while running runs are marked for cancellation and the worker terminates the active rsync process group. Make dry-run log paths run-specific and add a defensive default dry-run timeout so stuck dry-runs do not remain running indefinitely. Remove rsync exit codes from run overview tables while keeping detailed diagnostics available on the run detail payload.
This commit is contained in:
@@ -10,6 +10,7 @@ from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.conf import settings
|
||||
from django.db.models import Count
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from pobsync.errors import PobsyncError
|
||||
@@ -348,12 +349,37 @@ def run_detail(request, run_id: int):
|
||||
run = get_object_or_404(BackupRun.objects.select_related("host", "snapshot"), id=run_id)
|
||||
context = {
|
||||
"run": run,
|
||||
"can_cancel": run.status in {BackupRun.Status.QUEUED, BackupRun.Status.RUNNING},
|
||||
"requested": run.result.get("requested") if isinstance(run.result, dict) else {},
|
||||
"result_json": _pretty_json(run.result),
|
||||
}
|
||||
return render(request, "pobsync_backend/run_detail.html", context)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def cancel_run(request, run_id: int):
|
||||
run = get_object_or_404(BackupRun.objects.select_related("host"), id=run_id)
|
||||
if run.status not in {BackupRun.Status.QUEUED, BackupRun.Status.RUNNING}:
|
||||
messages.warning(request, f"Run {run.id} is already {run.status}.")
|
||||
return redirect("run_detail", run_id=run.id)
|
||||
|
||||
result = dict(run.result) if isinstance(run.result, dict) else {}
|
||||
result["cancellation"] = {
|
||||
"requested_at": timezone.now().isoformat(),
|
||||
"previous_status": run.status,
|
||||
}
|
||||
update_fields = ["status", "result"]
|
||||
run.status = BackupRun.Status.CANCELLED
|
||||
run.result = result
|
||||
if result["cancellation"]["previous_status"] == BackupRun.Status.QUEUED:
|
||||
run.ended_at = timezone.now()
|
||||
update_fields.append("ended_at")
|
||||
run.save(update_fields=update_fields)
|
||||
messages.success(request, f"Cancellation requested for run {run.id}.")
|
||||
return redirect("run_detail", run_id=run.id)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def snapshot_detail(request, snapshot_id: int):
|
||||
snapshot = get_object_or_404(
|
||||
|
||||
Reference in New Issue
Block a user