Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
911f043
feat: add manual discovery upstream status
Aias00 Apr 1, 2026
1041025
Update shenyu-admin/src/main/resources/mappers/discovery-upstream-sql…
Aias00 Apr 1, 2026
a0e40b2
Update shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/U…
Aias00 Apr 1, 2026
9648ac5
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 1, 2026
e74205b
fix: add discovery upstream manual status ddl
Aias00 Apr 2, 2026
f111247
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 2, 2026
315cec2
fix discovery upstream manual status fallback
Aias00 Apr 2, 2026
59ada22
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 14, 2026
ae77e1e
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 14, 2026
1722504
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 15, 2026
54bcd99
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 15, 2026
8993aca
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 24, 2026
53b999b
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 24, 2026
ba2aad1
Merge branch 'master' into feat/upstream-manual-status
Aias00 Apr 27, 2026
cbb516e
Merge branch 'master' into feat/upstream-manual-status
Aias00 May 8, 2026
47a3ff8
Merge branch 'master' into feat/upstream-manual-status
Aias00 May 12, 2026
d1ec4f4
Merge branch 'master' into feat/upstream-manual-status
Aias00 Jun 8, 2026
281cb25
Merge branch 'master' into feat/upstream-manual-status
Aias00 Jun 11, 2026
2fe4494
Merge branch 'master' into feat/upstream-manual-status
Aias00 Jun 11, 2026
846c77e
Merge branch 'master' into feat/upstream-manual-status
Aias00 Jun 12, 2026
1246512
Merge branch 'master' into feat/upstream-manual-status
Aias00 Jun 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions db/init/mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2425,6 +2425,7 @@ CREATE TABLE `discovery_upstream`
`protocol` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'for http, https, tcp, ws',
`upstream_url` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'ip:port',
`upstream_status` int(0) NOT NULL COMMENT 'type (0, healthy, 1 unhealthy)',
`manual_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NONE' COMMENT 'manual status (NONE, FORCE_OFFLINE)',
`weight` int(0) NOT NULL COMMENT 'the weight for lists',
`props` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'the other field (json)',
`date_created` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'create time',
Expand Down
1 change: 1 addition & 0 deletions db/init/ob/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2342,6 +2342,7 @@ CREATE TABLE `discovery_upstream`
`protocol` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'for http, https, tcp, ws',
`upstream_url` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'ip:port',
`upstream_status` int(0) NOT NULL COMMENT 'type (0, healthy, 1 unhealthy)',
`manual_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NONE' COMMENT 'manual status (NONE, FORCE_OFFLINE)',
`weight` int(0) NOT NULL COMMENT 'the weight for lists',
`props` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'the other field (json)',
`date_created` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'create time',
Expand Down
2 changes: 2 additions & 0 deletions db/init/og/create-table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,7 @@ CREATE TABLE "public"."discovery_upstream"
"protocol" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
"upstream_url" varchar(128) COLLATE "pg_catalog"."default",
"upstream_status" int4 NOT NULL,
"manual_status" varchar(32) COLLATE "pg_catalog"."default" NOT NULL DEFAULT 'NONE',
"weight" int4 NOT NULL,
"props" text COLLATE "pg_catalog"."default",
"date_created" timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
Expand All @@ -2535,6 +2536,7 @@ COMMENT ON COLUMN "public"."discovery_upstream"."namespace_id" IS 'namespace id'
COMMENT ON COLUMN "public"."discovery_upstream"."protocol" IS 'for http, https, tcp, ws';
COMMENT ON COLUMN "public"."discovery_upstream"."upstream_url" IS 'ip:port';
COMMENT ON COLUMN "public"."discovery_upstream"."upstream_status" IS 'type (0, healthy, 1 unhealthy)';
COMMENT ON COLUMN "public"."discovery_upstream"."manual_status" IS 'manual status (NONE, FORCE_OFFLINE)';
COMMENT ON COLUMN "public"."discovery_upstream"."weight" IS 'the weight for lists';
COMMENT ON COLUMN "public"."discovery_upstream"."props" IS 'the other field (json)';
COMMENT ON COLUMN "public"."discovery_upstream"."date_created" IS 'create time';
Expand Down
5 changes: 4 additions & 1 deletion db/init/oracle/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2732,6 +2732,7 @@ create table discovery_upstream
protocol VARCHAR2(64),
upstream_url VARCHAR2(64) not null,
upstream_status NUMBER(10) not null,
manual_status VARCHAR2(32) default 'NONE' not null,
weight NUMBER(10) not null,
props CLOB,
date_created timestamp(3) default SYSDATE not null,
Expand All @@ -2753,6 +2754,8 @@ comment on column DISCOVERY_UPSTREAM.upstream_url
is 'ip:port';
comment on column DISCOVERY_UPSTREAM.upstream_status
is 'type (0, healthy, 1 unhealthy)';
comment on column DISCOVERY_UPSTREAM.manual_status
is 'manual status (NONE, FORCE_OFFLINE)';
comment on column DISCOVERY_UPSTREAM.weight
is 'the weight for lists';
comment on column DISCOVERY_UPSTREAM.props
Expand Down Expand Up @@ -3813,4 +3816,4 @@ INSERT INTO permission (id, object_id, resource_id, date_created, date_updated)
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303902', '1346358560427216896', '1953048313980116901', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303903', '1346358560427216896', '1953048313980116902', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303904', '1346358560427216896', '1953048313980116903', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303905', '1346358560427216896', '1953048313980116904', sysdate, sysdate);
INSERT INTO permission (id, object_id, resource_id, date_created, date_updated) VALUES ('1953049887387303905', '1346358560427216896', '1953048313980116904', sysdate, sysdate);
2 changes: 2 additions & 0 deletions db/init/pg/create-table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2646,6 +2646,7 @@ CREATE TABLE "public"."discovery_upstream"
"protocol" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
"upstream_url" varchar(128) COLLATE "pg_catalog"."default",
"upstream_status" int4 NOT NULL,
"manual_status" varchar(32) COLLATE "pg_catalog"."default" NOT NULL DEFAULT 'NONE',
"weight" int4 NOT NULL,
"props" text COLLATE "pg_catalog"."default",
"date_created" timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
Expand All @@ -2658,6 +2659,7 @@ COMMENT ON COLUMN "public"."discovery_upstream"."namespace_id" IS 'the namespace
COMMENT ON COLUMN "public"."discovery_upstream"."protocol" IS 'for http, https, tcp, ws';
COMMENT ON COLUMN "public"."discovery_upstream"."upstream_url" IS 'ip:port';
COMMENT ON COLUMN "public"."discovery_upstream"."upstream_status" IS 'type (0, healthy, 1 unhealthy)';
COMMENT ON COLUMN "public"."discovery_upstream"."manual_status" IS 'manual status (NONE, FORCE_OFFLINE)';
COMMENT ON COLUMN "public"."discovery_upstream"."weight" IS 'the weight for lists';
COMMENT ON COLUMN "public"."discovery_upstream"."props" IS 'the other field (json)';
COMMENT ON COLUMN "public"."discovery_upstream"."date_created" IS 'create time';
Expand Down
20 changes: 20 additions & 0 deletions db/upgrade/2.7.1-upgrade-2.7.2-mysql.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- this file works for MySQL.
ALTER TABLE `discovery_upstream`
ADD COLUMN `manual_status` varchar(32) NOT NULL DEFAULT 'NONE' COMMENT 'manual status (NONE, FORCE_OFFLINE)'
AFTER `upstream_status`;
20 changes: 20 additions & 0 deletions db/upgrade/2.7.1-upgrade-2.7.2-ob.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- this file works for OceanBase.
ALTER TABLE `discovery_upstream`
ADD COLUMN `manual_status` varchar(32) NOT NULL DEFAULT 'NONE' COMMENT 'manual status (NONE, FORCE_OFFLINE)'
AFTER `upstream_status`;
21 changes: 21 additions & 0 deletions db/upgrade/2.7.1-upgrade-2.7.2-og.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- this file works for og.
ALTER TABLE "public"."discovery_upstream"
ADD COLUMN "manual_status" VARCHAR(32) NOT NULL DEFAULT 'NONE';

COMMENT ON COLUMN "public"."discovery_upstream"."manual_status" IS 'manual status (NONE, FORCE_OFFLINE)';
21 changes: 21 additions & 0 deletions db/upgrade/2.7.1-upgrade-2.7.2-oracle.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- this file works for Oracle, can not use "`" syntax.
ALTER TABLE discovery_upstream
ADD manual_status VARCHAR2(32) DEFAULT 'NONE' NOT NULL;

COMMENT ON COLUMN discovery_upstream.manual_status IS 'manual status (NONE, FORCE_OFFLINE)';
21 changes: 21 additions & 0 deletions db/upgrade/2.7.1-upgrade-2.7.2-pg.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- this file works for PostgreSQL, can not use "`" syntax.
ALTER TABLE "public"."discovery_upstream"
ADD COLUMN "manual_status" VARCHAR(32) NOT NULL DEFAULT 'NONE';

COMMENT ON COLUMN "public"."discovery_upstream"."manual_status" IS 'manual status (NONE, FORCE_OFFLINE)';
12 changes: 12 additions & 0 deletions db/upgrade/upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

## To Shenyu Users

- 2.7.1-upgrade-2.7.2-mysql.sql

- 2.7.1-upgrade-2.7.2-ob.sql

- 2.7.1-upgrade-2.7.2-og.sql

- 2.7.1-upgrade-2.7.2-oracle.sql

- 2.7.1-upgrade-2.7.2-pg.sql

> this file is the Shenyu upgrade sql from v2.7.1 to v2.7.2

- 2.7.0-upgrade-2.7.1-mysql.sql

- 2.7.0-upgrade-2.7.1-og.sql
Expand Down
88 changes: 88 additions & 0 deletions docs/superpowers/plans/2026-04-01-upstream-manual-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Upstream Manual Status Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add persisted manual upstream offline control and make Admin, sync payloads, and Gateway selection honor it end to end.

**Architecture:** Introduce a shared `UpstreamManualStatusEnum`, persist it on `discovery_upstream`, update Admin service/controller flows to publish sync events after manual changes, and carry the new field through sync DTOs into Gateway cache objects where load-balancer selection filters forced-offline upstreams.

**Tech Stack:** Java, Spring MVC, MyBatis, Maven, JUnit 5, Mockito

---

### Task 1: Add Failing Admin Tests

**Files:**
- Modify: `shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java`
- Modify: `shenyu-admin/src/test/java/org/apache/shenyu/admin/service/SyncDataServiceTest.java`
- Test: `shenyu-admin/src/test/java/org/apache/shenyu/admin/service/DiscoveryUpstreamServiceTest.java`

- [ ] **Step 1: Write failing tests for manual status update and status short-circuit**
- [ ] **Step 2: Write failing assertions that sync payload exposes `manualStatus`**
- [ ] **Step 3: Run admin tests to verify they fail for missing field and behavior**
- [ ] **Step 4: Keep failures focused on the new contract**

### Task 2: Add Failing Gateway Tests

**Files:**
- Modify: `shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/factory/LoadBalancerFactoryTest.java`
- Modify: `shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/handler/DivideUpstreamDataHandlerTest.java`
- Test: `shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/factory/LoadBalancerFactoryTest.java`

- [ ] **Step 1: Add a failing load-balancer test that excludes `FORCE_OFFLINE` upstreams**
- [ ] **Step 2: Add a failing divide handler test that maps sync payload `manualStatus` into cached upstreams**
- [ ] **Step 3: Run targeted gateway tests to verify red state**

### Task 3: Implement Shared Enum And DTO Changes

**Files:**
- Create: `shenyu-common/src/main/java/org/apache/shenyu/common/enums/UpstreamManualStatusEnum.java`
- Modify: `shenyu-common/src/main/java/org/apache/shenyu/common/dto/DiscoveryUpstreamData.java`
- Modify: `shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java`

- [ ] **Step 1: Add the shared enum with `NONE` and `FORCE_OFFLINE`**
- [ ] **Step 2: Extend sync DTO and cached upstream entity with `manualStatus`**
- [ ] **Step 3: Keep defaults backward compatible with `NONE`**

### Task 4: Implement Admin Persistence And API

**Files:**
- Modify: `shenyu-admin/src/main/resources/sql-script/h2/schema.sql`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/DiscoveryUpstreamDO.java`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/DiscoveryUpstreamDTO.java`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/model/vo/DiscoveryUpstreamVO.java`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapper.java`
- Modify: `shenyu-admin/src/main/resources/mappers/discovery-upstream-sqlmap.xml`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DiscoveryTransfer.java`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/service/DiscoveryUpstreamService.java`
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryUpstreamServiceImpl.java`
- Create: `shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/UpstreamManualStatusDTO.java`
- Create: `shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/UpstreamController.java`

- [ ] **Step 1: Persist `manual_status` and map it through DO/DTO/VO/Mapper**
- [ ] **Step 2: Add service methods to change manual status and publish fresh discovery events**
- [ ] **Step 3: Add `/upstream/offline` and `/upstream/online` controller endpoints**

### Task 5: Implement Heartbeat Short-Circuit And Gateway Filtering

**Files:**
- Modify: `shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java`
- Modify: `shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/handler/DivideUpstreamDataHandler.java`
- Modify: `shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-websocket/src/main/java/org/apache/shenyu/plugin/websocket/handler/WebSocketUpstreamDataHandler.java`
- Modify: `shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-grpc/src/main/java/org/apache/shenyu/plugin/grpc/handler/GrpcDiscoveryUpstreamDataHandler.java`
- Modify: `shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/factory/LoadBalancerFactory.java`

- [ ] **Step 1: Prevent alive/status recovery when the DB record is `FORCE_OFFLINE`**
- [ ] **Step 2: Map synced `manualStatus` into plugin-specific upstream cache objects**
- [ ] **Step 3: Filter forced-offline upstreams before selection**

### Task 6: Verify Green State

**Files:**
- Modify: `docs/superpowers/specs/2026-04-01-upstream-manual-status-design.md`
- Modify: `docs/superpowers/plans/2026-04-01-upstream-manual-status.md`

- [ ] **Step 1: Run targeted Maven tests for admin, loadbalancer, and divide modules**
- [ ] **Step 2: Run a focused compile if any cross-module breakage appears**
- [ ] **Step 3: Review git diff for unintended changes**
- [ ] **Step 4: Commit with one feature commit**
Loading
Loading