Skip to content

[BUG] Cancelling a backup marks it cancelled but leaves restic running #1155

Description

@EthanC

Prerequisites

Rclone Pre-flight Checklist (if applicable)

  • This issue is NOT related to rclone (skip if not using rclone)
  • I have tested rclone listremotes and rclone lsd remote: on the host and they work
  • I have verified the rclone config is mounted into the container
  • I have restarted the container after config changes

Bug Description

Cancelling a running backup changes the task status to cancelled, but the restic process continues running and uploading data. In my test, the process remained active until I terminated it manually.

The likely cause is the module-local execution registry in app/server/modules/tasks/tasks.lifecycle.ts:

const taskExecutions = new Map<string, TaskExecution>();

Nitro can load the task runner and cancellation route from separate server bundles. The cancellation route then sees no matching execution and follows this branch:

if (!execution) {
    taskStore.cancel(taskId, TASK_CANCELLED_ERROR);
    return true;
}

This marks the task cancelled without calling execution.cancel(). The running process continues, while the UI and database report that it stopped.

The execution registry should be shared across server bundles, similar to the process-wide task listener state added in #1146. For example:

type ProcessWithTaskExecutions = NodeJS.Process & {
    __zerobyteTaskExecutions?: Map<string, TaskExecution>;
};

const runtimeProcess = process as ProcessWithTaskExecutions;
const taskExecutions = (runtimeProcess.__zerobyteTaskExecutions ??= new Map());

safeSpawn should also resolve only after the child emits close. Resolving immediately from its error handler can release task and repository state before the OS process has exited.

Steps to Reproduce

  1. Start a backup large enough to remain active for several minutes.
  2. Confirm that restic and its backend process are running with docker top.
  3. Cancel the backup from the Zerobyte UI.
  4. Observe that the task immediately changes to cancelled.
  5. Run docker top again.
  6. Observe that restic and its backend process are still running and continue transferring data.

Expected Behavior

The task should enter cancelling, signal the registered execution, and remain in that state until the child process closes. It should change to cancelled only after restic has exited.

Zerobyte version / commit

v0.42.0 - b87c59b

Deployment Method

Docker Compose

Backup/Repository Context

  • Repository type: rclone
  • Storage backend: Proton Drive
  • Backup operation: Folders containing image files
  • Restic version: 0.19.1
  • Rclone version during reproduction: 1.75.1

The cancellation failure occurs in Zerobyte before the backend process is signaled, so it is not specific to Proton Drive or rclone.

Logs / Error Messages

Zerobyte marked the task cancelled, then continued receiving progress from the running backup:

Failed to persist backup task progress for <task-id>:
Task <task-id> was not updated with progress; current status is cancelled

The database row showed:

status: cancelled
cancellation_requested: 1
error: Task was cancelled by the user
outcome: cancelled

The processes were still running afterward:

/usr/local/bin/restic --repo rclone:Proton:Backup/Immich backup ...
rclone serve restic --stdio ... Proton:Backup/Immich

Both processes stopped only after manual termination.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions