Skip to content

feat: add remote service migration - #5195

Open
DenisHoppe wants to merge 1 commit into
Dokploy:canaryfrom
DenisHoppe:feat/remote-service-migration-canary
Open

feat: add remote service migration#5195
DenisHoppe wants to merge 1 commit into
Dokploy:canaryfrom
DenisHoppe:feat/remote-service-migration-canary

Conversation

@DenisHoppe

@DenisHoppe DenisHoppe commented Aug 26, 2026

Copy link
Copy Markdown

Summary

  • add remote project duplication and two-phase Application moves with explicit source cleanup
  • add full-data Compose and PostgreSQL/MySQL/MariaDB/MongoDB/Redis/LibSQL moves using streamed transfers
  • persist migration phases and owned artifacts for safe retry, rollback, collision prevention, source preservation, and deletion guards
  • support local and remote monitoring consistently
  • reject unsafe bind/anonymous/external mount scenarios and require explicit cleanup

This port is based directly on the remote migration work from a1dfb1a7f, 070de6adc, and 6f0195a5e, adapted to current Canary APIs. It is independent of AutoDNS, does not include the AutoDNS commits, and does not depend on codex/autodns-provider.

Related context: DenisHoppe/dokploy#1 and DenisHoppe/dokploy#2.

Validation

  • pnpm --filter @dokploy/server typecheck
  • pnpm --filter dokploy typecheck
  • Biome check on all changed TypeScript/TSX/JSON files
  • focused migration suite: 13 files, 98 tests passed
  • locally executable full suite: 110 files, 982 tests passed
  • full suite: 981 passed, 1 skipped; 5 environment-dependent tests could not run because Docker and Nixpacks are unavailable locally

Greptile Summary

This PR adds durable, two-phase remote moves for Compose and managed database services, including streamed data transfer, target collision protection, explicit finalization, rollback, and dashboard controls.

  • Adds migration records and phase/ownership metadata for retry and cleanup.
  • Streams Compose directories and persistent volumes between local or remote servers.
  • Adds move, rollback, and finalize APIs and corresponding dashboard workflows.
  • Extends local/remote monitoring behavior and guards conflicting service operations.

Confidence Score: 3/5

The PR should not merge until migration recovery cannot lose track of ownership changes or newly created target artifacts.

Separate writes can leave service placement inconsistent with migration state after interruption, while unrecorded target volumes or directories survive rollback and block safe retries.

Files Needing Attention: packages/server/src/services/compose-move.ts, packages/server/src/services/database-move.ts, packages/server/src/utils/migration/transfer.ts

Reviews (1): Last reviewed commit: "feat: add remote service migration" | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Context used (3)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment on lines +432 to +440
await updateCompose(composeId, {
serverId: normalizedTargetServerId,
serviceNetworks: [],
});
ownershipMoved = true;
await updateServiceMigrationProgress(migrationRow.serviceMigrationId, {
phase: "ownership_moved",
ownershipMoved: true,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Ownership state diverges

If the process exits or the progress write fails after serverId is updated, ownershipMoved remains false, so rollback restarts the workload on the source without restoring its record from the target. The migration row is then deleted, leaving Dokploy managing the wrong server while an orphaned workload runs on the source. The database move at database-move.ts:402-410 has the same split write.

Knowledge Base Used:

);
}

await onTargetCreated?.();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Artifact ownership is lost

If the process exits or onTargetCreated fails after the target volume is created, its name is never persisted and this helper does not remove it. Recovery therefore omits the volume, which can contain partial data and blocks later migrations at the collision check; the directory path at line 154 has the same gap.

Knowledge Base Used: Managed databases and storage

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant