Skip to content

Cleanup: fix deletion hang - #176

Merged
darkmuggle merged 2 commits into
mainfrom
bh/clean-up
Aug 11, 2026
Merged

Cleanup: fix deletion hang#176
darkmuggle merged 2 commits into
mainfrom
bh/clean-up

Conversation

@darkmuggle

Copy link
Copy Markdown
Contributor

Part 1 in a serious of deletion handling.

Deleting a RestateDeployment hangs forever due to conflating is active to mean:

  • "is a service pointed at this deployment"
  • "are there active invocations"

This change seperates those two facts and considers them differently depending on why the drain is happening (rollout vs deletion).

Additionally, a few other issues feel out:

  1. The drain requeue deadline was being thrown away do an error policy wrapping the finalizer.
  2. A draining version kept its autoscaler. HPA removal has been moved to the point where we actually scale to zero.

References #172

Part 1 in a serious of deletion handling.

Deleting a RestateDeployment hangs forever due to conflating
is active to mean:
* "is a service pointed at this deployment"
* "are there active invocations"

This change seperates those two facts and considers them
differently depending on why the drain is happening (rollout vs
deletion).

Additionally, a few other issues feel out:
1. The drain requeue deadline was being thrown away do an error
   policy wrapping the finalizer.
2. A draining version kept its autoscaler. HPA removal has been
   moved to the point where we actually scale to zero.

References #172
@socket-security

socket-security Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedcargo/​opentelemetry-otlp@​0.31.1 ⏵ 0.32.09710093100100
Updatedcargo/​tracing-opentelemetry@​0.32.1 ⏵ 0.33.0100 +110093100100

View full report

@pcholakov
pcholakov self-requested a review August 10, 2026 16:37
Comment thread src/controllers/restatedeployment/controller.rs Outdated
Comment thread src/controllers/restatedeployment/reconcilers/replicaset.rs
Comment thread src/controllers/restatedeployment/cleanup.rs
Comment thread release-notes/unreleased/172-restatedeployment-deletion-hang.md
Comment on lines +29 to +30
- **A blocked deletion says what is blocking it.** The `DeploymentInUse` event now names
each version and its pinned/unpinned invocation counts instead of a generic message.

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.

This is very neat!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After this lands, the next PR is for a richer status including the inflight innovations.

@pcholakov

Copy link
Copy Markdown
Contributor

Thanks for tackling this, @darkmuggle!

The biggest thing that is missing for me here is an e2e test – I believe it's time we added some that run in-tree.

I'm worried about the cost of querying sys_invocation_status in environments with a lot of retained invocations; definitely should look at an EXPLAIN plan and see if we can optimize that – more detail inline.

It's probably worth following up with #174, or at least taking into consideration how that would be solved. We had an external contributor open PR #160; this PR supersedes its data model (splitting the single active flag into separate facts) but not its actual fix, which was on the registration path – so #174 is currently unowned. That PR would need substantial rework to merge on top of this, and may not be the approach we want anyway.

darkmuggle added a commit that referenced this pull request Aug 10, 2026
- Build the deployment-usage query in Rust rather than sharing one string
  behind a `WHERE 1 = 0` guard. DataFusion does fold the guard away (EXPLAIN
  against 1.7.2 shows the unpinned scan disappearing), but the reconcile path
  should not depend on an optimiser pass across server versions we don't pin.
  The rollout flavour now scans sys_invocation_status once, with projection
  [status, pinned_deployment_id] -- no target_service_name decode.
- Restore the note explaining the COALESCE/LEFT JOIN pairing, and move the row
  parsing next to the query it belongs to.
- Back off a blocked deletion: retries stretch from 30s to a 5m cap as the wait
  grows, instead of re-running the deleting query every 30s forever.
- Cover the teardown ordering with mocked-apiserver tests: the HPA comes off
  immediately before the scale to zero, and not while a version is still
  waiting out its drain deadline (in a rollout or a deletion).
- Add e2e tests that run both query flavours against a real Restate server in a
  container, and parse the rows through the operator's own row struct. Wired
  into CI, which was not running cargo test at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
darkmuggle added a commit that referenced this pull request Aug 10, 2026
- Build the deployment-usage query in Rust rather than sharing one string
  behind a `WHERE 1 = 0` guard. DataFusion does fold the guard away (EXPLAIN
  against 1.7.2 shows the unpinned scan disappearing), but the reconcile path
  should not depend on an optimiser pass across server versions we don't pin.
  The rollout flavour now scans sys_invocation_status once, with projection
  [status, pinned_deployment_id] -- no target_service_name decode.
- Restore the note explaining the COALESCE/LEFT JOIN pairing, and move the row
  parsing next to the query it belongs to.
- Back off a blocked deletion: retries stretch from 30s to a 5m cap as the wait
  grows, instead of re-running the deleting query every 30s forever.
- Cover the teardown ordering with mocked-apiserver tests: the HPA comes off
  immediately before the scale to zero, and not while a version is still
  waiting out its drain deadline (in a rollout or a deletion).
- Run cargo test in CI, which was not running tests at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Build the deployment-usage query in Rust rather than sharing one string
  behind a `WHERE 1 = 0` guard. DataFusion does fold the guard away (EXPLAIN
  against 1.7.2 shows the unpinned scan disappearing), but the reconcile path
  should not depend on an optimiser pass across server versions we don't pin.
  The rollout flavour now scans sys_invocation_status once, with projection
  [status, pinned_deployment_id] -- no target_service_name decode.
- Restore the note explaining the COALESCE/LEFT JOIN pairing, and move the row
  parsing next to the query it belongs to.
- Back off a blocked deletion: retries stretch from 30s to a 5m cap as the wait
  grows, instead of re-running the deleting query every 30s forever.
- Cover the teardown ordering with mocked-apiserver tests: the HPA comes off
  immediately before the scale to zero, and not while a version is still
  waiting out its drain deadline (in a rollout or a deletion).
- Run cargo test in CI, which was not running tests at all.
@darkmuggle

Copy link
Copy Markdown
Contributor Author

@pcholakov new push with the changes. I'll get a separate PR for the E2E tests. I did test the SQL against a local Restate cluster.

@darkmuggle
darkmuggle merged commit 17dae4a into main Aug 11, 2026
6 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants