Skip to content

fix(instance): align persisted state labels across admin and dashboard - #7889

Open
cloudbase-ai wants to merge 2 commits into
apache:masterfrom
cloudbase-ai:fix/issue-7694-instance-state
Open

cloudbase-ai wants to merge 2 commits into
apache:masterfrom
cloudbase-ai:fix/issue-7694-instance-state

Conversation

@cloudbase-ai

Copy link
Copy Markdown
Contributor

Fixes #7694. Dashboard source companion: apache/shenyu-dashboard#727.

Instance state 0 has always meant DELETED in the backend, but the shipped dashboard and schema comments call it unknown. Unrecognized numeric states are also reported as DELETED by the backend enum fallback.

Keep the persisted contract (0=DELETED, 1=ONLINE, 2=OFFLINE) and the existing timeout/recovery transitions. Return UNKNOWN for unrecognized values without adding a new numeric state, correct fresh-schema comments, and update existing column descriptions in the 2.7.2→2.7.3 scripts. Historical stored values are not rewritten. Document that Deleted is a retained expired-instance state, rather than physical row removal.

Include the generated Admin dashboard bundle from apache/shenyu-dashboard@f239397e67c970c25a769f3b41ad3aaa7aca7a72 (source PR apache/shenyu-dashboard#727). The source baseline is 370cc40095ef4aa820449b7a9b736c7c98b6e9ab, which is already the baseline bundled by Admin. Only the JavaScript bundle and its HTML reference change; CSS and other assets are unchanged. Build provenance and SHA-256 are recorded in docs/instance-state-contract.md, and the copied static files were compared byte for byte with the build output. Please merge the dashboard source companion first.

Validation:

  • ./mvnw -pl shenyu-admin -am test -Dtest=InstanceStatusEnumTest,InstanceCheckServiceTest,InstanceInfoServiceTest,InstanceInfoMapperTest,InstanceControllerTest -Dsurefire.failIfNoSpecifiedTests=false -Drat.skip=true -Djacoco.skip=true -Dmaven.javadoc.skip=true — 54 tests, no failures/errors; Checkstyle passed.
  • ./mvnw -pl shenyu-common,shenyu-admin apache-rat:check — passed.
  • Dashboard npm test — 58 suites, 340 tests passed; focused ESLint passed; npm run build passed.
  • Regression tests distinguish deleted/unknown chart entries, pin all persisted enum codes, preserve raw unrecognized values, and exercise online→offline→deleted→online recovery.

The mapper checks use H2. Native MySQL/OceanBase/PostgreSQL/openGauss/Oracle upgrade scripts and a live Admin heartbeat/dashboard end-to-end deployment were not run.

Aias00
Aias00 previously approved these changes Oct 21, 2026

@Aias00 Aias00 left a comment

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.

Review: label alignment for persisted instance states

The core of this change is correct, and I verified each claim against the code rather than the description:

  • InstanceStatusEnum still pins 0=DELETED, 1=ONLINE, 2=OFFLINE, and values().length == 3, so no new persisted code is introduced and historical rows stay valid.
  • The only production caller of getNameByCode is InstanceCheckService#getInstanceDataVisual: line data passes the literal 0/1/2, and pie data passes arbitrary codes. So changing the fallback from DELETED.name to UNKNOWN cannot affect the timeout/recovery transitions in doCheck(), which compare against getCode() only.
  • Schema comments, the five dialect upgrade scripts, the H2 schema and the new contract doc all agree on the same code table.
  • The frontend change is a clean bundle swap (index.16dee401.js deleted, index.72158727.js added, index.html reference updated) with provenance recorded.

A note on the upgrade scripts: db/upgrade/2.7.2-upgrade-2.7.3-*.sql was introduced two days ago by #7673 and master is still 2.7.2-SNAPSHOT, so editing those files in place is fine here — nobody has consumed them from a release yet. MODIFY COLUMN / COMMENT ON COLUMN are both idempotent, and the definition repeats the existing type and NOT NULL with no default, so re-running is harmless.

Non-blocking comments

  1. Pie data can emit duplicate UNKNOWN slices. getInstanceDataVisual groups by state code first, then maps each code to a name, so two distinct unrecognized codes (e.g. 3 and 99) produce two separate entries that both render as UNKNOWN. If the contract is "unknown is a presentation fallback, not a state", group by the mapped name instead:

    Map<String, Long> pieData = instanceInfoVOS.stream()
            .filter(instance -> Objects.nonNull(instance.getInstanceState()))
            .collect(Collectors.groupingBy(vo -> InstanceStatusEnum.getNameByCode(vo.getInstanceState()),
                    Collectors.counting()));

    The new test only exercises a single unknown code, so this case is not covered today.

  2. "UNKNOWN" is a magic string in a shared enum. shenyu-common is consumed outside Admin, and the dashboard contract now depends on this exact literal. Consider exposing it as a documented constant (e.g. public static final String UNKNOWN_STATE_NAME = "UNKNOWN") so the doc, the enum and InstanceStatusEnumTest cannot drift apart. Keeping it out of the enum constants is the right call — a real constant would collide with the persisted-code space — but that rationale is worth a line in the Javadoc.

  3. Compatibility note for downstream consumers. getNameByCode previously never returned a value outside the enum; after this change it can return UNKNOWN. Anything downstream that switches on the returned string (or assumes it is a known state name) will now see a new value. The contract doc covers the semantics, but it deserves a line in the release notes too, since this is a public API in shenyu-common.

  4. Nit: testExpiryAndRecoveryKeepPersistedStateCodes mutates instanceHeartBeatTimeOut / deleteTimeout via ReflectionTestUtils. That is safe here because the class builds a fresh InstanceCheckService per test with MockitoExtension (no shared Spring context), but if this test class ever moves to @SpringBootTest those fields will leak into sibling tests.

LGTM apart from the above. The docs/instance-state-contract.md write-up is a good addition — it makes the retained-expired-record semantics explicit, which is exactly what was missing when the dashboard labeled 0 as unknown.

@Aias00

Aias00 commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Heads-up: this branch now has merge conflicts with master (mergeStateStatus: DIRTY), so CI can no longer validate it against the current base.

The conflict is almost certainly in the SQL migration set, which moves often:
db/init/{mysql,oracle,pg}/schema.sql, db/upgrade/2.7.2-upgrade-2.7.3-{mysql,ob,og,oracle,pg}.sql.

Could you rebase onto master and regenerate the upgrade scripts against the current schema (rather than hand-resolving them), so the 7 dialect variants stay consistent? Once pushed I will re-run the review and merge if the build is green.

@Aias00

Aias00 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Heads-up: this branch conflicts with master and update-branch cannot resolve it, so a manual rebase is needed.

A large batch of admin/instance-related PRs merged in the last hour (#7762-series instance handling, #7780, #7776, #7962 namespace carry-over on appauth delete, #7855, #7888), several of which touch the same instance state / label persistence paths. Please rebase on master and re-run CI — the approval stands.

@Aias00 Aias00 left a comment

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.

Re-approving after the master merge. The change only corrects the persisted state labels to match InstanceStatusEnum (0 = DELETED), and keeps every stored numeric value and transition untouched. The upgrade scripts only rewrite the column comment, so no data migration is required. The contract document makes the DELETED-vs-unknown distinction explicit, which is what the dashboard mismatch needed.

One coordination note: this PR also rebuilds the bundled dashboard artifacts, which overlaps the scope of #8003. Whichever lands first, please make sure the second one is dropped or rebased so the static bundle is not replaced twice.

@Aias00

Aias00 commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

@cloudbase-ai This PR is approved, but 1 checks are red: build (shenyu-integrated-test-http).

I inspected these lanes today and they fail for infrastructure reasons rather than on the diff — the integrated-test jobs die while starting their containers (Elasticsearch /_cat/health returning 000 until the job is cancelled), and the http lane also hits the known CachePluginTest.testMemoryModle / testRedisModle flake. The same jobs are red on master and on unrelated PRs right now.

Please rebase onto master and push (or ask for a re-run) so the checks execute again. If a case is still failing on a fresh run, paste the test name and I'll look properly.

@Aias00

Aias00 commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Hi @cloudbase-ai, this PR is already approved, but it currently cannot be merged. Here is the blocker and what is needed:

Blocker
This PR is unmergeable (conflict) against master. Separately, build (shenyu-integrated-test-http) fails in CachePluginTest.testRedisModle / testMemoryModle (AssertionFailedError at CachePluginTest.java:73) - the identical failure also reproduces on unrelated PRs (#7888, #7895), so it is a systemic/flaky cache test, not your diff.

What we need
Please rebase onto the latest master, resolve conflicts, and re-run; treat CachePluginTest as infra flakiness unless it reproduces in isolation.

Once the branch is up to date and CI is green, we will squash-merge it. Thanks!

This branch has not been deployed

No deployments
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.

[BUG] Instance state code zero means DELETED in backend but UNKNOWN in dashboard

2 participants