Skip to content

feat(frontend): delete rivet compute pool when its runner config is deleted - #5709

Open
abcxff wants to merge 1 commit into
stack/feat-frontend-allow-disabling-rivet-compute-for-a-project-xnoyxmxofrom
stack/feat-frontend-delete-rivet-compute-pool-when-its-runner-config-is-deleted-yzpyzolo
Open

abcxff wants to merge 1 commit into
stack/feat-frontend-allow-disabling-rivet-compute-for-a-project-xnoyxmxofrom
stack/feat-frontend-delete-rivet-compute-pool-when-its-runner-config-is-deleted-yzpyzolo

Conversation

@abcxff

@abcxff abcxff commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@abcxff

abcxff commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

@the-company-company the-company-company Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 1 medium-severity finding

Reviewed commit 166b74d.

mutationFn: async (name: string) => {
await deleteRunnerConfig(name);
const { managedPools } =
await parent.client.managedPools.list(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Medium · Find the matching pool beyond the first page

managedPools.list is paginated (the repository's Cloud CLI requests limit=100 and follows pagination.cursor), but this lookup fetches only its first response. If a namespace has enough pools for the target name to be on a later page, the runner config is deleted and find returns nothing, leaving the managed pool running despite this mutation reporting success. Request a sufficiently bounded page or follow cursors until the matching name is found.

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Review

Single-file change to frontend/src/app/data-providers/cloud-data-provider.tsx: it overrides the engine namespace context's deleteRunnerConfigMutationOptions so deleting a runner config also tears down its matching Rivet Compute managed pool. The refactor of engineContext into a named variable (instead of an inline spread) is clean and needed to call the base mutation.

Correctness: deletion order is not retry-safe

mutationFn (cloud-data-provider.tsx:1420-1447) does, in order:

  1. deleteRunnerConfig(name) deletes the engine runner config.
  2. Lists managed pools and, if a match is found, deletes the pool.

If step 2 fails (network blip, transient API error, etc.), step 1 has already succeeded, so the runner config is gone but the pool is now permanently stranded from the UI perspective. Clicking Delete again in confirm-delete-config-frame.tsx will retry deleteRunnerConfig(name) first, which will now fail (config already gone) before ever reaching the pool-deletion step. This defeats the exact problem the PR is meant to fix: the comment above the override says deleting only the config would strand the managed pool, but a partial failure here produces the same stranded outcome, and the UI no longer offers an idempotent way to retry it.

Deleting the pool first, then the runner config, would make the flow idempotent: if the pool delete fails, nothing has changed yet and a retry redoes both steps; if the runner config delete then fails, a retry of managedPools.list finds no matching pool and skips straight to (successfully) retrying the config delete.

Minor: defensive check on an unreachable case

const base = engineContext.deleteRunnerConfigMutationOptions();
if (!base.mutationFn) {
    throw new Error("engine runner config delete mutation is not configured");
}

engine-data-provider.tsx's deleteRunnerConfigMutationOptions always sets mutationFn, so this branch cannot actually happen; it exists only to satisfy the optional mutationFn type from mutationOptions(). Per this repo guidance to trust internal code and framework guarantees, a non-null assertion (base.mutationFn!) with a short comment would be simpler than a throwable runtime check for a case that cannot occur.

Other notes

  • The candidate.status !== "destroying" skip and looking up the pool by name === config name matches the existing pattern in disableComputeMutationOptions in the same file, so that part is consistent.
  • No test coverage was added, but that matches the rest of this file (no data-provider tests exist for the sibling mutations either), so it is not a regression specific to this change.

Overall a small, focused change. The main thing worth addressing before merge is the deletion ordering for retry-safety.

@abcxff
abcxff force-pushed the stack/feat-frontend-delete-rivet-compute-pool-when-its-runner-config-is-deleted-yzpyzolo branch from 166b74d to 4804d6b Compare September 14, 2026 14:44
@abcxff
abcxff force-pushed the stack/feat-frontend-allow-disabling-rivet-compute-for-a-project-xnoyxmxo branch from c090ba5 to 4316084 Compare September 14, 2026 14:44

@the-company-company the-company-company Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 2 medium-severity findings

Reviewed commit 4804d6b.

...opts,
mutationKey: base.mutationKey,
mutationFn: async (name: string) => {
await deleteRunnerConfig(name);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Medium · Keep the config until pool cleanup starts

The runner config is removed before the managed-pool lookup and delete. A transient Cloud API failure after this line leaves the pool alive but removes the only UI path that can retry its cleanup: retrying the dialog first attempts the now-missing config and fails. Look up and begin deleting the matching pool before deleting its runner config, so any failure leaves a retryable state.

mutationFn: async (name: string) => {
await deleteRunnerConfig(name);
const { managedPools } =
await parent.client.managedPools.list(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Medium · Find the matching pool beyond the first page

managedPools.list is paginated (the repository's Cloud CLI requests limit=100 and follows pagination.cursor), but this lookup fetches only its first response. If a namespace has enough pools for the target name to be on a later page, the runner config is deleted and find returns nothing, leaving the managed pool running despite this mutation reporting success. Request a bounded page or follow cursors until the matching name is found.

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