Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -2444,6 +2444,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 @@ -2361,6 +2361,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 @@ -2542,6 +2542,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 @@ -2554,6 +2555,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 @@ -2733,6 +2733,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 @@ -2754,6 +2755,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 @@ -3815,4 +3818,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 @@ -2665,6 +2665,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 @@ -2677,6 +2678,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