Skip to content

feat(servers): split Delete and Disconnect, and make Delete reliable - #172

Merged
ericwang401 merged 4 commits into
4.xfrom
feat/server-delete-disconnect
Oct 16, 2026
Merged

ericwang401 merged 4 commits into
4.xfrom
feat/server-delete-disconnect

Conversation

@ericwang401

@ericwang401 ericwang401 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Changes

  • Delete always removes everything: backups (locked ones included), then the VM, then the Convoy entry. If the VM is already gone from the node, it just removes the Convoy entry. A failed delete can be retried from deletion_failed. Delete is refused (409) only while another operation is running on the server or a backup is in progress.
  • Disconnect replaces the "Do not purge" checkbox. It's an outline button next to Delete that removes the Convoy entry and leaves the VM and its backups on the node. It works from any state, so it's the way out for a server stuck on "Deleting". Both buttons also appear on the admin "Deleting" / "Failed to Delete" screen.
  • API unchanged: DELETE with no_purge still disconnects.
  • Safer "VM is gone" check: only Proxmox's own "does not exist" response now counts as a missing VM, through a new ServerBuildService::vmExists(). Before, any Proxmox error counted, so a node that was briefly unreachable could get a server removed from Convoy while its VM kept running.

Testing

  • Pest: 16 new tests covering:
    • the shape of the delete chain
    • an outage leaving the server untouched
    • retrying from deletion_failed
    • busy states being refused
    • disconnecting from any state
    • the failure handler
    • forced purging of locked backups
    • vmExists()
  • Real Proxmox node: deleted a server whose VM was present (the VM was destroyed), deleted one whose VM had been removed by hand, and disconnected one.

Notes

isVmDeleted() returns true for any ProxmoxConnectionException -- a 401, a
503, a proxy error -- so WaitUntilVmIsDeletedJob could conclude a VM was
gone while the node was merely unreachable, and the deletion chain would
then drop the server from Convoy with its VM still running.

Add vmExists(), which returns false only for Proxmox's 500 "Configuration
file ... does not exist" and rethrows anything else, and use it in
WaitUntilVmIsDeletedJob. That job also gets a 5s backoff, so an outage is
retried at a sane pace rather than in a tight loop.
Delete now always removes everything and can't get stuck:
- backups are purged with force, so a locked backup no longer fails it;
- when the VM is already gone from the node (vmExists), only the Convoy
  entry is removed instead of failing on "does not exist";
- it's allowed from deletion_failed, so a failed delete can be retried;
- it's refused (409) only while another chain is running on the server,
  or a backup is in progress;
- the failure handler writes by ID, like build/rebuild.

The "Do not purge" checkbox becomes a Disconnect button (outline, next to
Delete): it removes the Convoy entry and leaves the VM and backups on the
node, from any state -- the way out for a server stuck on "Deleting". The
API stays compatible: DELETE with no_purge disconnects. Both buttons also
show on the admin's "Deleting"/"Failed to Delete" screen, since the
settings page isn't reachable in those states.

Tested with Pest (chain shapes, outage leaves the server alone, retry
from deletion_failed, busy states refused, disconnect from any state,
failure handler, forced purge, vmExists) and on a real Proxmox node:
delete with the VM present, delete with it already removed, disconnect.
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Contributor License Agreement

All identified human contributors have signed the current CLA.

isVmMissingError() read the response off the RequestException that ProxmoxConnectionException wrapped. #176 stops wrapping it and keeps the response on the exception instead, so read $e->response first and fall back to the wrapped one. The "does not exist" check then works whichever of the two PRs merges first; #172's tests pass against both versions of the exception.
@ericwang401
ericwang401 merged commit d37fc42 into 4.x Oct 16, 2026
2 checks passed
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