Skip to content

Add Helix REST guard rails for known rebalance-failure scenarios (CICP-3788) - #204

Draft
arkmish wants to merge 3 commits into
devfrom
armishra/cicp-3788-helix-rest-guard-rails-design
Draft

Add Helix REST guard rails for known rebalance-failure scenarios (CICP-3788)#204
arkmish wants to merge 3 commits into
devfrom
armishra/cicp-3788-helix-rest-guard-rails-design

Conversation

@arkmish

@arkmish arkmish commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Issues

  • My PR addresses the following Helix issues and references them in the PR description:

Tracked internally as JIRA CICP-3788 — "Identify guard rails in Helix REST for known failure scenarios". There is no public GitHub issue; this is the first code increment for that work, preceded by a design doc.

Description

  • Here are some details about my PR, including screenshots of any UI changes:

What: adds pre-flight "guard rails" to mutating Helix REST endpoints that reject operations which would make the cluster un-rebalanceable, plus the design doc that scopes the effort.

Why: operations like dropping an instance or shrinking instance capacity are accepted unconditionally today and only fail later, on the controller's next WAGED rebalance (min-active-replica / capacity violations), far from the API call that caused them.

How:

  1. New helix-core RebalanceFeasibilityEvaluator — a ZooKeeper-free invariant checker over a computed (un-applied) assignment, with FeasibilityResult / FeasibilityViolation value types. Checks: min-active-replica, WAGED instance capacity, and no-unassigned-partition, plus a merge to aggregate per-check results. Reuses the canonical definitions in WagedValidationUtil and InstanceValidationUtil.
  2. Wired into helix-rest PerInstanceAccessor, enforce-by-default with a ?force=true bypass and a uniform 400 response carrying violation details:
    • DELETE /clusters/{c}/instances/{n} — runs the min-active-replica check on a post-drop assignment derived from each resource's current ExternalView.
    • POST /clusters/{c}/instances/{n}/configs (update command) — simulates the persisted ZNRecord.merge and runs the capacity check; no-ops on non-WAGED clusters.

This is the first increment; remaining guard rails (add-resource, ACM stoppable, EVACUATE placement-recompute) are follow-ups described in the design doc.

Tests

  • The following tests are written for this issue:

  • helix-core: TestRebalanceFeasibilityEvaluator — 12 cases (min-active-replica flagged/satisfied/unset/multi; capacity missing-key/present/no-keys; no-unassigned missing/empty/assigned; merge aggregate/all-feasible). Built test-first (TDD).

  • helix-rest: TestPerInstanceAccessor#testDeleteInstanceMinActiveReplicaGuardRail and #testUpdateInstanceConfigCapacityGuardRail — each asserts the block (400) and the ?force=true bypass (200) through the full REST + embedded-ZK stack.

  • Local code review completed

  • The following is the result of the "mvn test" command on the appropriate module:

# helix-core
mvn test -pl helix-core -Dtest=TestRebalanceFeasibilityEvaluator
Tests run: 12, Failures: 0, Errors: 0, Skipped: 0

# helix-rest (full class, regression check)
mvn test -pl helix-rest -Dtest=TestPerInstanceAccessor
Tests run: 37, Failures: 0, Errors: 0, Skipped: 0

Changes that Break Backward Compatibility (Optional)

  • My PR contains changes that break backward compatibility or previous assumptions for certain methods or API. They include:

  • DELETE /clusters/{c}/instances/{n} now returns 400 instead of 200 when dropping the instance would push a hosted partition below minActiveReplicas. Callers that must proceed can pass ?force=true to preserve the prior behavior.

  • POST /clusters/{c}/instances/{n}/configs (update) now returns 400 instead of 200 when the merged config would be missing a required WAGED capacity key. Same ?force=true bypass. Non-WAGED clusters are unaffected (the check no-ops).

Both endpoints gained an additive force query param (default false); existing query strings are unaffected.

Documentation (Optional)

  • In case of new functionality, my PR adds documentation in the following wiki page:

Design doc added in-repo at docs/design/002-helix-rest-guard-rails.md (follows docs/design/000-TEMPLATE.md).

Commits

  • My commits all reference appropriate Apache Helix GitHub issues in their subject lines. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Code Quality

  • My diff has been formatted using helix-style.xml
    (helix-style-intellij.xml if IntelliJ IDE is used)

🤖 Generated with GitHub Copilot CLI

arkmish and others added 3 commits June 24, 2026 11:47
Scoping design for guard rails on known rebalance-failure scenarios in Helix REST: instance removal/capacity shrink, ACM stoppable-check completeness, EVACUATE, and resource onboarding. Recommends a shared RebalanceFeasibilityEvaluator in helix-core that reuses existing 'compute assignment without applying' primitives (the same ones behind ResourceAssignmentOptimizerAccessor). Documents code placement, helix-rest integration, customer usage/migration, testing strategy, and backward compatibility (enforce-by-default + force bypass).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the helix-core foundation from docs/design/002: a ZooKeeper-free
invariant checker over a computed (un-applied) rebalancer assignment, plus
FeasibilityResult / FeasibilityViolation value types.

Checks:
- min-active-replica: flags partitions that would drop below minActiveReplicas,
  using the same active/unhealthy-state definition as InstanceValidationUtil.
- WAGED capacity: reuses WagedValidationUtil.validateAndGetInstanceCapacity to
  flag instances missing required capacity keys; no-ops on non-WAGED clusters.
- no-unassigned-partition: flags expected partitions left unassigned.
- FeasibilityResult.merge aggregates per-check results for the REST layer.

Built test-first; TestRebalanceFeasibilityEvaluator covers all four with 12
cases. REST accessor wiring (PerInstanceAccessor / ResourceAccessor / ACM
stoppable) and the ZK-bound assignment computation are follow-ups.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ls (CICP-3788)

Implements Step 2 of docs/design/002: pre-flight guard rails on two mutating
PerInstanceAccessor endpoints, each enforced by default with a ?force=true bypass.

- deleteInstance: derives a post-drop assignment from each resource's current
  ExternalView and runs the evaluator's min-active-replica check (using the same
  active/unhealthy-state definition as the controller). Returns 400 when dropping
  the instance would push a hosted partition below minActiveReplicas.
- updateInstanceConfig (update command): simulates the persisted ZNRecord.merge and
  runs the evaluator's capacity check. Returns 400 when the merged config would be
  missing a required WAGED capacity key. No-ops on non-WAGED clusters.

Both return a uniform 400 with violation details. Adds two integration tests to
TestPerInstanceAccessor (block + force-bypass for each); full class (37 tests) green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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