This is an automated email from the ASF dual-hosted git repository.

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 759ea514bb fix: Non-default HTTP retry backoff strategies cannot be 
selected (#6529)
759ea514bb is described below

commit 759ea514bbda8d5216044683c1696e58c7b8c655
Author: hengyuss <[email protected]>
AuthorDate: Fri Sep 18 17:48:15 2026 +0800

    fix: Non-default HTTP retry backoff strategies cannot be selected (#6529)
    
    * fix: Non-default HTTP retry backoff strategies cannot be selected
    
    * fix: add tests, fix sort conflict, and hide custom backoff strategy
    
    - Add HttpRetryBackoffSpecEnumTest for acquireByName coverage
    - Add retryBackOffSpec getter/setter test in DivideRuleHandleTest
    - Add DividePluginTest assertions for HTTP_RETRY_BACK_OFF_SPEC attribute
    - Fix plugin_handle sort conflict: retryBackOffSpec sort 0→1
    - Disable custom dict entry (enabled 1→0) in all SQL dialects
    - Remove CUSTOM_BACKOFF enum value and CustomRetryStrategy class
    - Remove CUSTOM_BACKOFF case from AbstractHttpClientPlugin switch
    
    * test: add tests
    
    * fix: fix tests
    
    * trigger CI
    
    * fix: delete `custom` in shenyu.dict
    
    * fix: fix tests
    
    ---------
    
    Co-authored-by: Liming Deng <[email protected]>
---
 db/init/mysql/schema.sql                           |  4 ++
 db/init/ob/schema.sql                              |  4 ++
 db/init/og/create-table.sql                        |  4 ++
 db/init/oracle/schema.sql                          | 13 ++++++
 db/init/pg/create-table.sql                        |  4 ++
 db/upgrade/2.7.0-upgrade-2.7.1-mysql.sql           |  6 +++
 db/upgrade/2.7.0-upgrade-2.7.1-ob.sql              |  6 +++
 db/upgrade/2.7.0-upgrade-2.7.1-og.sql              |  6 +++
 db/upgrade/2.7.0-upgrade-2.7.1-oracle.sql          | 10 +++++
 db/upgrade/2.7.0-upgrade-2.7.1-pg.sql              |  6 +++
 .../src/main/resources/sql-script/h2/schema.sql    |  4 ++
 .../apache/shenyu/common/constant/Constants.java   |  2 +-
 .../dto/convert/rule/impl/DivideRuleHandle.java    | 21 +++++++--
 .../common/enums/HttpRetryBackoffSpecEnum.java     |  7 +--
 .../convert/rule/impl/DivideRuleHandleTest.java    |  3 ++
 .../common/enums/HttpRetryBackoffSpecEnumTest.java | 52 ++++++++++++++++++++++
 .../httpclient/AbstractHttpClientPlugin.java       | 11 ++---
 .../plugin/httpclient/CustomRetryStrategy.java     | 51 ---------------------
 .../apache/shenyu/plugin/divide/DividePlugin.java  |  2 +
 .../shenyu/plugin/divide/DividePluginTest.java     | 32 ++++++++++++-
 20 files changed, 179 insertions(+), 69 deletions(-)

diff --git a/db/init/mysql/schema.sql b/db/init/mysql/schema.sql
index d88db8536d..1810760524 100644
--- a/db/init/mysql/schema.sql
+++ b/db/init/mysql/schema.sql
@@ -1102,6 +1102,7 @@ INSERT INTO `plugin_handle` VALUES 
('1529402613199978551', '5', 'multiRuleHandle
 INSERT INTO `plugin_handle` VALUES ('1529402613199978552', '5', 
'headerMaxSize', 'headerMaxSize', 1, 2, 3, 
'{\"defaultValue\":\"10240\",\"rule\":\"\"}', '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978553', '5', 
'requestMaxSize', 'requestMaxSize', 1, 2, 4, 
'{\"defaultValue\":\"102400\",\"rule\":\"\"}', '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978554', '5', 
'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{\"required\":\"0\",\"defaultValue\":\"current\",\"placeholder\":\"retryStrategy\",\"rule\":\"\"}',
 '2022-05-25 18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `plugin_handle` VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{\"required\":\"0\",\"defaultValue\":\"default\",\"placeholder\":\"retryBackOffSpec\",\"rule\":\"\"}',
 '2026-07-31 18:02:53', '2026-07-31 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978555', '13', 
'upstreamHost', 'host', 2, 1, 0, NULL, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978556', '13', 'protocol', 
'protocol', 2, 1, 2, '{\"defaultValue\":\"\",\"rule\":\"\"}', '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978557', '13', 
'upstreamUrl', 'ip:port', 2, 1, 1, 
'{\"required\":\"1\",\"placeholder\":\"\",\"rule\":\"\"}', '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
@@ -2279,6 +2280,9 @@ INSERT INTO `shenyu_dict` VALUES ('1529402613195784237', 
'threadpool', 'THREADPO
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784238', 'threadpool', 
'THREADPOOL', 'limited', 'limited', '', 1, 1, '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784239', 'retryStrategy', 
'RETRY_STRATEGY', 'current', 'current', 'current', 0, 1, '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784240', 'retryStrategy', 
'RETRY_STRATEGY', 'failover', 'failover', 'failover', 1, 1, '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784250', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 1, '2026-07-31 
18:02:53', '2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784251', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, '2026-07-31 18:02:53', 
'2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784252', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 'exponential', 2, 1, 
'2026-07-31 18:02:53', '2026-07-31 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784241', 'table', 'INIT_FLAG', 
'status', 'true', 'table(resource,permission) init status', 0, 0, '2022-05-25 
18:02:53', '2022-05-25 18:02:58');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784242', 'compressAlg', 
'COMPRESS_ALG', 'none', 'none', '', 0, 1, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784243', 'compressAlg', 
'COMPRESS_ALG', 'LZ4', 'LZ4', '', 1, 1, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
diff --git a/db/init/ob/schema.sql b/db/init/ob/schema.sql
index 2f259975fe..9741b14b0e 100644
--- a/db/init/ob/schema.sql
+++ b/db/init/ob/schema.sql
@@ -1069,6 +1069,7 @@ INSERT INTO `plugin_handle` VALUES 
('1529402613199978551', '5', 'multiRuleHandle
 INSERT INTO `plugin_handle` VALUES ('1529402613199978552', '5', 
'headerMaxSize', 'headerMaxSize', 1, 2, 3, 
'{\"defaultValue\":\"10240\",\"rule\":\"\"}', '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978553', '5', 
'requestMaxSize', 'requestMaxSize', 1, 2, 4, 
'{\"defaultValue\":\"102400\",\"rule\":\"\"}', '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978554', '5', 
'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{\"required\":\"0\",\"defaultValue\":\"current\",\"placeholder\":\"retryStrategy\",\"rule\":\"\"}',
 '2022-05-25 18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `plugin_handle` VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{\"required\":\"0\",\"defaultValue\":\"default\",\"placeholder\":\"retryBackOffSpec\",\"rule\":\"\"}',
 '2022-05-25 18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978555', '13', 
'upstreamHost', 'host', 2, 1, 0, NULL, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978556', '13', 'protocol', 
'protocol', 2, 1, 2, '{\"defaultValue\":\"\",\"rule\":\"\"}', '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `plugin_handle` VALUES ('1529402613199978557', '13', 
'upstreamUrl', 'ip:port', 2, 1, 1, 
'{\"required\":\"1\",\"placeholder\":\"\",\"rule\":\"\"}', '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
@@ -2209,6 +2210,9 @@ INSERT INTO `shenyu_dict` VALUES ('1529402613195784237', 
'threadpool', 'THREADPO
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784238', 'threadpool', 
'THREADPOOL', 'limited', 'limited', '', 1, 1, '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784239', 'retryStrategy', 
'RETRY_STRATEGY', 'current', 'current', 'current', 0, 1, '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784240', 'retryStrategy', 
'RETRY_STRATEGY', 'failover', 'failover', 'failover', 1, 1, '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784250', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 1, '2022-05-25 
18:02:53', '2022-05-25 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784251', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, '2022-05-25 18:02:53', 
'2022-05-25 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784252', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 'exponential', 2, 1, 
'2022-05-25 18:02:53', '2022-05-25 18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784241', 'table', 'INIT_FLAG', 
'status', 'true', 'table(resource,permission) init status', 0, 0, '2022-05-25 
18:02:53', '2022-05-25 18:02:58');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784242', 'compressAlg', 
'COMPRESS_ALG', 'none', 'none', '', 0, 1, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784243', 'compressAlg', 
'COMPRESS_ALG', 'LZ4', 'LZ4', '', 1, 1, '2022-05-25 18:02:53', '2022-05-25 
18:02:53');
diff --git a/db/init/og/create-table.sql b/db/init/og/create-table.sql
index 97a90b57fe..7f28716848 100644
--- a/db/init/og/create-table.sql
+++ b/db/init/og/create-table.sql
@@ -1090,6 +1090,7 @@ INSERT INTO "public"."plugin_handle" VALUES 
('1529403902779330564', '5', 'multiR
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330565', '5', 
'headerMaxSize', 'headerMaxSize', 1, 2, 3, 
'{"defaultValue":"10240","rule":""}', '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330566', '5', 
'requestMaxSize', 'requestMaxSize', 1, 2, 4, 
'{"defaultValue":"102400","rule":""}', '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330567', '5', 
'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{"required":"0","defaultValue":"current","placeholder":"retryStrategy","rule":""}',
 '2022-05-25 18:08:01', '2022-05-25 18:08:01');
+INSERT INTO "public"."plugin_handle" VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}',
 '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330568', '13', 
'upstreamHost', 'host', 2, 1, 0, NULL, '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330569', '13', 
'protocol', 'protocol', 2, 1, 2, '{"defaultValue":"","rule":""}', '2022-05-25 
18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330570', '13', 
'upstreamUrl', 'ip:port', 2, 1, 1, 
'{"required":"1","placeholder":"","rule":""}', '2022-05-25 18:08:01', 
'2022-05-25 18:08:01');
@@ -2165,6 +2166,9 @@ INSERT INTO "public"."shenyu_dict" VALUES 
('1529403902800302089', 'threadpool',
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302090', 
'threadpool', 'THREADPOOL', 'limited', 'limited', '', 1, 1, '2022-05-25 
18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302091', 
'retryStrategy', 'RETRY_STRATEGY', 'current', 'current', 'current', 0, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302092', 
'retryStrategy', 'RETRY_STRATEGY', 'failover', 'failover', 'failover', 1, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784250', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 
1, '2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784251', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784252', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 
'exponential', 2, 1, '2022-05-25 18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302094', 
'compressAlg', 'COMPRESS_ALG', 'none', 'none', '', 0, 1, '2022-05-25 18:08:02', 
'2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302095', 
'compressAlg', 'COMPRESS_ALG', 'LZ4', 'LZ4', '', 1, 1, '2022-05-25 18:08:02', 
'2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302096', 'cacheType', 
'CACHE_TYPE_MEMORY', 'memory', 'memory', 'use memory to cache data', 0, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
diff --git a/db/init/oracle/schema.sql b/db/init/oracle/schema.sql
index aa44e96a33..8bb7ebadd2 100644
--- a/db/init/oracle/schema.sql
+++ b/db/init/oracle/schema.sql
@@ -1089,6 +1089,16 @@ values ('1518229897206079525', 'retryStrategy', 
'RETRY_STRATEGY', 'current', 'cu
 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
 values ('1518229897206079526', 'retryStrategy', 'RETRY_STRATEGY', 'failover', 
'failover', 'failover', 1, 1);
 
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
+values ('1529402613195784250', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'default', 'default', 'default', 0, 1);
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
+values ('1529402613195784251', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'fixed', 'fixed', 'fixed', 1, 1);
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
+values ('1529402613195784252', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'exponential', 'exponential', 'exponential', 2, 1);
+
+
 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
 values ('1518229897206079527', 'table', 'INIT_FLAG', 'status', 'false', 
'table(resource,permission) init status', 0, 0);
 
@@ -1595,6 +1605,9 @@ values ('1518229897210273844', '5', 'requestMaxSize', 
'requestMaxSize', 1, 2, 4,
 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) 
*/ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, 
EXT_OBJ)
 values ('1518229897210273845', '5', 'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{"required":"0","defaultValue":"current","placeholder":"retryStrategy","rule":""}');
 
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) 
*/ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, 
EXT_OBJ)
+values ('1529402613199979560', '5', 'retryBackOffSpec', 'retryBackOffSpec', 3, 
2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}');
+
 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) 
*/ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, 
EXT_OBJ)
 values ('1518229897210273846', '13', 'upstreamHost', 'host', 2, 1, 0, null);
 
diff --git a/db/init/pg/create-table.sql b/db/init/pg/create-table.sql
index f8e452297a..5cbf6c4df3 100644
--- a/db/init/pg/create-table.sql
+++ b/db/init/pg/create-table.sql
@@ -1148,6 +1148,7 @@ INSERT INTO "public"."plugin_handle" VALUES 
('1529403902779330564', '5', 'multiR
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330565', '5', 
'headerMaxSize', 'headerMaxSize', 1, 2, 3, 
'{"defaultValue":"10240","rule":""}', '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330566', '5', 
'requestMaxSize', 'requestMaxSize', 1, 2, 4, 
'{"defaultValue":"102400","rule":""}', '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330567', '5', 
'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{"required":"0","defaultValue":"current","placeholder":"retryStrategy","rule":""}',
 '2022-05-25 18:08:01', '2022-05-25 18:08:01');
+INSERT INTO "public"."plugin_handle" VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}',
 '2022-05-25 18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330568', '13', 
'upstreamHost', 'host', 2, 1, 0, NULL, '2022-05-25 18:08:01', '2022-05-25 
18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330569', '13', 
'protocol', 'protocol', 2, 1, 2, '{"defaultValue":"","rule":""}', '2022-05-25 
18:08:01', '2022-05-25 18:08:01');
 INSERT INTO "public"."plugin_handle" VALUES ('1529403902779330570', '13', 
'upstreamUrl', 'ip:port', 2, 1, 1, 
'{"required":"1","placeholder":"","rule":""}', '2022-05-25 18:08:01', 
'2022-05-25 18:08:01');
@@ -2289,6 +2290,9 @@ INSERT INTO "public"."shenyu_dict" VALUES 
('1529403902800302089', 'threadpool',
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302090', 
'threadpool', 'THREADPOOL', 'limited', 'limited', '', 1, 1, '2022-05-25 
18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302091', 
'retryStrategy', 'RETRY_STRATEGY', 'current', 'current', 'current', 0, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302092', 
'retryStrategy', 'RETRY_STRATEGY', 'failover', 'failover', 'failover', 1, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784250', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 
1, '2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784251', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784252', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 
'exponential', 2, 1, '2022-05-25 18:08:02', '2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302094', 
'compressAlg', 'COMPRESS_ALG', 'none', 'none', '', 0, 1, '2022-05-25 18:08:02', 
'2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302095', 
'compressAlg', 'COMPRESS_ALG', 'LZ4', 'LZ4', '', 1, 1, '2022-05-25 18:08:02', 
'2022-05-25 18:08:02');
 INSERT INTO "public"."shenyu_dict" VALUES ('1529403902800302096', 'cacheType', 
'CACHE_TYPE_MEMORY', 'memory', 'memory', 'use memory to cache data', 0, 1, 
'2022-05-25 18:08:02', '2022-05-25 18:08:02');
diff --git a/db/upgrade/2.7.0-upgrade-2.7.1-mysql.sql 
b/db/upgrade/2.7.0-upgrade-2.7.1-mysql.sql
index 978b4b53e7..7f9ce09ac3 100755
--- a/db/upgrade/2.7.0-upgrade-2.7.1-mysql.sql
+++ b/db/upgrade/2.7.0-upgrade-2.7.1-mysql.sql
@@ -360,3 +360,9 @@ DELETE FROM `namespace_plugin_rel` WHERE `plugin_id` = '17';
 DELETE FROM `plugin_handle` WHERE `plugin_id` = '17';
 DELETE FROM `plugin` WHERE `id` = '17';
 ALTER TABLE `api` MODIFY COLUMN `rpc_type` varchar(64) CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 
'http,dubbo,sofa,tars,websocket,springCloud,grpc';
+
+INSERT INTO `plugin_handle` VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{\"required\":\"0\",\"defaultValue\":\"default\",\"placeholder\":\"retryBackOffSpec\",\"rule\":\"\"}',
 '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784250', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 1, '2026-07-31 
18:02:53', '2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784251', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, '2026-07-31 18:02:53', 
'2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784252', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 'exponential', 2, 1, 
'2026-07-31 18:02:53', '2026-07-31 18:02:53');
diff --git a/db/upgrade/2.7.0-upgrade-2.7.1-ob.sql 
b/db/upgrade/2.7.0-upgrade-2.7.1-ob.sql
index 6b8aac0afa..792719b3aa 100755
--- a/db/upgrade/2.7.0-upgrade-2.7.1-ob.sql
+++ b/db/upgrade/2.7.0-upgrade-2.7.1-ob.sql
@@ -352,3 +352,9 @@ DELETE FROM `namespace_plugin_rel` WHERE `plugin_id` = '17';
 DELETE FROM `plugin_handle` WHERE `plugin_id` = '17';
 DELETE FROM `plugin` WHERE `id` = '17';
 ALTER TABLE `api` MODIFY COLUMN `rpc_type` varchar(64) CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 
'http,dubbo,sofa,tars,websocket,springCloud,grpc';
+
+INSERT INTO `plugin_handle` VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{\"required\":\"0\",\"defaultValue\":\"default\",\"placeholder\":\"retryBackOffSpec\",\"rule\":\"\"}',
 '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784250', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 1, '2026-07-31 
18:02:53', '2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784251', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, '2026-07-31 18:02:53', 
'2026-07-31 18:02:53');
+INSERT INTO `shenyu_dict` VALUES ('1529402613195784252', 'retryBackOffSpec', 
'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 'exponential', 2, 1, 
'2026-07-31 18:02:53', '2026-07-31 18:02:53');
diff --git a/db/upgrade/2.7.0-upgrade-2.7.1-og.sql 
b/db/upgrade/2.7.0-upgrade-2.7.1-og.sql
index 36f6b4e122..5794093625 100644
--- a/db/upgrade/2.7.0-upgrade-2.7.1-og.sql
+++ b/db/upgrade/2.7.0-upgrade-2.7.1-og.sql
@@ -380,3 +380,9 @@ DELETE FROM "public"."namespace_plugin_rel" WHERE 
"plugin_id" = '17';
 DELETE FROM "public"."plugin_handle" WHERE "plugin_id" = '17';
 DELETE FROM "public"."plugin" WHERE "id" = '17';
 COMMENT ON COLUMN "public"."api"."rpc_type" IS 
'http,dubbo,sofa,tars,websocket,springCloud,grpc';
+
+INSERT INTO "public"."plugin_handle" VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}',
 '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784250', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 
1, '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784251', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, 
'2026-07-31 18:02:53', '2026-07-31 18:02:53');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784252', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 
'exponential', 2, 1, '2026-07-31 18:02:53', '2026-07-31 18:02:53');
diff --git a/db/upgrade/2.7.0-upgrade-2.7.1-oracle.sql 
b/db/upgrade/2.7.0-upgrade-2.7.1-oracle.sql
index c3ec9c2f9c..5aef068397 100755
--- a/db/upgrade/2.7.0-upgrade-2.7.1-oracle.sql
+++ b/db/upgrade/2.7.0-upgrade-2.7.1-oracle.sql
@@ -735,3 +735,13 @@ DELETE FROM namespace_plugin_rel WHERE plugin_id = '17';
 DELETE FROM plugin_handle WHERE plugin_id = '17';
 DELETE FROM plugin WHERE id = '17';
 COMMENT ON COLUMN api.rpc_type IS 
'http,dubbo,sofa,tars,websocket,springCloud,grpc';
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin_handle(plugin_id, field, type)) 
*/ into plugin_handle (ID, PLUGIN_ID, FIELD, LABEL, DATA_TYPE, TYPE, SORT, 
EXT_OBJ)
+values ('1529402613199979560', '5', 'retryBackOffSpec', 'retryBackOffSpec', 3, 
2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}');
+
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into shenyu_dict (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "DESC", SORT, 
ENABLED)
+values ('1529402613195784250', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'default', 'default', 'default', 0, 1);
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into shenyu_dict (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "DESC", SORT, 
ENABLED)
+values ('1529402613195784251', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'fixed', 'fixed', 'fixed', 1, 1);
+insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ into shenyu_dict (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "DESC", SORT, 
ENABLED)
+values ('1529402613195784252', 'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 
'exponential', 'exponential', 'exponential', 2, 1);
diff --git a/db/upgrade/2.7.0-upgrade-2.7.1-pg.sql 
b/db/upgrade/2.7.0-upgrade-2.7.1-pg.sql
index eca5d2cc53..55ee08a4ce 100755
--- a/db/upgrade/2.7.0-upgrade-2.7.1-pg.sql
+++ b/db/upgrade/2.7.0-upgrade-2.7.1-pg.sql
@@ -378,3 +378,9 @@ DELETE FROM "public"."namespace_plugin_rel" WHERE 
"plugin_id" = '17';
 DELETE FROM "public"."plugin_handle" WHERE "plugin_id" = '17';
 DELETE FROM "public"."plugin" WHERE "id" = '17';
 COMMENT ON COLUMN "public"."api"."rpc_type" IS 
'http,dubbo,sofa,tars,websocket,springCloud,grpc';
+
+INSERT INTO "public"."plugin_handle" VALUES ('1529402613199979560', '5', 
'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}',
 '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784250', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 
1, '2026-07-31 18:02:53', '2026-07-31 18:02:53');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784251', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1, 
'2026-07-31 18:02:53', '2026-07-31 18:02:53');
+INSERT INTO "public"."shenyu_dict" VALUES ('1529402613195784252', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 
'exponential', 2, 1, '2026-07-31 18:02:53', '2026-07-31 18:02:53');
diff --git a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql 
b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
index c38496b3e4..95e3f9951a 100644
--- a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
+++ b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
@@ -494,6 +494,9 @@ INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, 
`dict_name`, `dict_v
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784238', 
'threadpool', 'THREADPOOL', 'limited', 'limited', '', 1, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784239', 
'retryStrategy', 'RETRY_STRATEGY', 'current', 'current', 'current', 0, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784240', 
'retryStrategy', 'RETRY_STRATEGY', 'failover', 'failover', 'failover', 1, 1);
+INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784250', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'default', 'default', 'default', 0, 
1);
+INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784251', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'fixed', 'fixed', 'fixed', 1, 1);
+INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784252', 
'retryBackOffSpec', 'RETRY_BACKOFF_SPEC', 'exponential', 'exponential', 
'exponential', 2, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784241', 
'table', 'INIT_FLAG', 'status', 'false', 'table(resource,permission) init 
status', 0, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784242', 
'compressAlg', 'COMPRESS_ALG', 'none', 'none', '', 0, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1529402613195784243', 
'compressAlg', 'COMPRESS_ALG', 'LZ4', 'LZ4', '', 1, 1);
@@ -670,6 +673,7 @@ INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199978552', '5', 'headerMaxSize', 'headerMaxSize', 1, 2, 3, 
'{"defaultValue":"10240","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199978553', '5', 'requestMaxSize', 'requestMaxSize', 1, 2, 4, 
'{"defaultValue":"102400","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199978554', '5', 'retryStrategy', 'retryStrategy', 3, 2, 0, 
'{"required":"0","defaultValue":"current","placeholder":"retryStrategy","rule":""}');
+INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199979560', '5', 'retryBackOffSpec', 'retryBackOffSpec', 3, 2, 1, 
'{"required":"0","defaultValue":"default","placeholder":"retryBackOffSpec","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`) VALUES 
('1529402613199978555', '13', 'upstreamHost', 'host', 2, 1, 0);
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199978556', '13', 'protocol', 'protocol', 2, 1, 2, 
'{"defaultValue":"","rule":""}');
 INSERT IGNORE INTO plugin_handle (`id`, 
`plugin_id`,`field`,`label`,`data_type`,`type`,`sort`,`ext_obj`) VALUES 
('1529402613199978557', '13', 'upstreamUrl', 'ip:port', 2, 1, 1, 
'{"required":"1","placeholder":"","rule":""}');
diff --git 
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java 
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
index c852bfe5a9..ccc6c0e36c 100644
--- 
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
+++ 
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
@@ -1011,7 +1011,7 @@ public interface Constants {
     /**
      * Http request retry policy.
      */
-    String HTTP_RETRY_BACK_OFF_SPEC = "default";
+    String HTTP_RETRY_BACK_OFF_SPEC = "httpRetryBackOffSpec";
 
     /**
      * The constant Content.
diff --git 
a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandle.java
 
b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandle.java
index 20b1864bd9..84be0832c1 100644
--- 
a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandle.java
+++ 
b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandle.java
@@ -19,6 +19,7 @@ package org.apache.shenyu.common.dto.convert.rule.impl;
 
 import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.dto.convert.rule.RuleHandle;
+import org.apache.shenyu.common.enums.HttpRetryBackoffSpecEnum;
 import org.apache.shenyu.common.enums.LoadBalanceEnum;
 import org.apache.shenyu.common.enums.RetryEnum;
 
@@ -41,6 +42,8 @@ public class DivideRuleHandle implements RuleHandle {
      */
     private String retryStrategy = RetryEnum.CURRENT.getName();
 
+    private String retryBackOffSpec = HttpRetryBackoffSpecEnum.getDefault();
+
     /**
      * http retry.
      */
@@ -178,6 +181,14 @@ public class DivideRuleHandle implements RuleHandle {
         this.requestMaxSize = requestMaxSize;
     }
 
+    public String getRetryBackOffSpec() {
+        return retryBackOffSpec;
+    }
+
+    public void setRetryBackOffSpec(final String retryBackOffSpec) {
+        this.retryBackOffSpec = retryBackOffSpec;
+    }
+
     @Override
     public boolean equals(final Object o) {
         if (this == o) {
@@ -189,12 +200,13 @@ public class DivideRuleHandle implements RuleHandle {
         DivideRuleHandle that = (DivideRuleHandle) o;
         return retry == that.retry && timeout == that.timeout && headerMaxSize 
== that.headerMaxSize
                 && requestMaxSize == that.requestMaxSize && 
Objects.equals(loadBalance, that.loadBalance)
-                && Objects.equals(retryStrategy, that.retryStrategy);
+                && Objects.equals(retryStrategy, that.retryStrategy)
+                && Objects.equals(retryBackOffSpec, that.retryBackOffSpec);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(loadBalance, retryStrategy, retry, timeout, 
headerMaxSize, requestMaxSize);
+        return Objects.hash(loadBalance, retryStrategy, retryBackOffSpec, 
retry, timeout, headerMaxSize, requestMaxSize);
     }
 
     @Override
@@ -203,9 +215,12 @@ public class DivideRuleHandle implements RuleHandle {
                 + "loadBalance='"
                 + loadBalance
                 + '\''
-                + "retryStrategy='"
+                + ", retryStrategy='"
                 + retryStrategy
                 + '\''
+                + ", retryBackOffSpec='"
+                + retryBackOffSpec
+                + '\''
                 + ", retry="
                 + retry
                 + ", timeout="
diff --git 
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnum.java
 
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnum.java
index f3583503e9..511456d0ce 100644
--- 
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnum.java
+++ 
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnum.java
@@ -37,12 +37,7 @@ public enum HttpRetryBackoffSpecEnum {
     /**
      * Exponential retry.
      */
-    EXPONENTIAL_BACKOFF("exponential"),
-
-    /**
-     * Custom retry.
-     */
-    CUSTOM_BACKOFF("custom");
+    EXPONENTIAL_BACKOFF("exponential");
 
     private final String name;
 
diff --git 
a/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandleTest.java
 
b/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandleTest.java
index 1b11ee10f0..e705b66269 100644
--- 
a/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandleTest.java
+++ 
b/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/rule/impl/DivideRuleHandleTest.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.common.dto.convert.rule.impl;
 
 import com.google.common.collect.ImmutableSet;
+import org.apache.shenyu.common.enums.HttpRetryBackoffSpecEnum;
 import org.apache.shenyu.common.enums.LoadBalanceEnum;
 import org.apache.shenyu.common.enums.RetryEnum;
 import org.junit.jupiter.api.Test;
@@ -37,6 +38,7 @@ public class DivideRuleHandleTest {
         
         handle.setLoadBalance(LoadBalanceEnum.HASH.getName());
         handle.setRetryStrategy(RetryEnum.FAILOVER.getName());
+        
handle.setRetryBackOffSpec(HttpRetryBackoffSpecEnum.FIXED_BACKOFF.getName());
         handle.setRetry(1);
         handle.setTimeout(1000L);
         handle.setHeaderMaxSize(100L);
@@ -44,6 +46,7 @@ public class DivideRuleHandleTest {
         
         assertThat(handle.getLoadBalance(), 
is(LoadBalanceEnum.HASH.getName()));
         assertThat(handle.getRetryStrategy(), 
is(RetryEnum.FAILOVER.getName()));
+        assertThat(handle.getRetryBackOffSpec(), 
is(HttpRetryBackoffSpecEnum.FIXED_BACKOFF.getName()));
         assertThat(handle.getRetry(), is(1));
         assertThat(handle.getTimeout(), is(1000L));
         assertThat(handle.getHeaderMaxSize(), is(100L));
diff --git 
a/shenyu-common/src/test/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnumTest.java
 
b/shenyu-common/src/test/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnumTest.java
new file mode 100644
index 0000000000..454d70328f
--- /dev/null
+++ 
b/shenyu-common/src/test/java/org/apache/shenyu/common/enums/HttpRetryBackoffSpecEnumTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package org.apache.shenyu.common.enums;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class HttpRetryBackoffSpecEnumTest {
+
+    @Test
+    public void testAcquireByName() {
+        assertEquals(HttpRetryBackoffSpecEnum.DEFAULT_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName(HttpRetryBackoffSpecEnum.DEFAULT_BACKOFF.getName()));
+        assertEquals(HttpRetryBackoffSpecEnum.FIXED_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName(HttpRetryBackoffSpecEnum.FIXED_BACKOFF.getName()));
+        assertEquals(HttpRetryBackoffSpecEnum.EXPONENTIAL_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName(HttpRetryBackoffSpecEnum.EXPONENTIAL_BACKOFF.getName()));
+    }
+
+    @Test
+    public void testAcquireByNameNull() {
+        assertEquals(HttpRetryBackoffSpecEnum.DEFAULT_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName(null));
+    }
+
+    @Test
+    public void testAcquireByNameEmpty() {
+        assertEquals(HttpRetryBackoffSpecEnum.DEFAULT_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName(""));
+    }
+
+    @Test
+    public void testAcquireByNameUnknown() {
+        assertEquals(HttpRetryBackoffSpecEnum.DEFAULT_BACKOFF, 
HttpRetryBackoffSpecEnum.acquireByName("notExist"));
+    }
+
+    @Test
+    public void testGetDefault() {
+        assertEquals("default", HttpRetryBackoffSpecEnum.getDefault());
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
index dd624417c9..ed67c79ceb 100644
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
@@ -81,18 +81,15 @@ public abstract class AbstractHttpClientPlugin<R> 
implements ShenyuPlugin {
                 .timeout(duration, Mono.error(() -> new 
TimeoutException("Response took longer than timeout: " + duration)))
                 .doOnError(e -> LOG.error(e.getMessage(), e));
         RetryStrategy<R> strategy;
-        //Is it better to go with the configuration file here?
         String retryStrategyType = (String) 
Optional.ofNullable(exchange.getAttribute(Constants.HTTP_RETRY_BACK_OFF_SPEC)).orElse(HttpRetryBackoffSpecEnum.getDefault());
-        switch (retryStrategyType) {
-            case "exponential":
+        HttpRetryBackoffSpecEnum spec = 
HttpRetryBackoffSpecEnum.acquireByName(retryStrategyType);
+        switch (spec) {
+            case EXPONENTIAL_BACKOFF:
                 strategy = new ExponentialRetryBackoffStrategy<>(this);
                 break;
-            case "fixed":
+            case FIXED_BACKOFF:
                 strategy = new FixedRetryStrategy<>(this);
                 break;
-            case "custom":
-                strategy = new CustomRetryStrategy<>(this);
-                break;
             default:
                 strategy = new DefaultRetryStrategy<>(this);
         }
diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/CustomRetryStrategy.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/CustomRetryStrategy.java
deleted file mode 100644
index cd98b498d5..0000000000
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/CustomRetryStrategy.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.shenyu.plugin.httpclient;
-
-import java.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-/**
- *  Custom retry policy.
- *      Also please achieve your own
- */
-public class CustomRetryStrategy<R> implements RetryStrategy<R> {
-    private static final Logger LOG = 
LoggerFactory.getLogger(CustomRetryStrategy.class);
-
-    private final AbstractHttpClientPlugin<R> httpClientPlugin;
-
-    public CustomRetryStrategy(final AbstractHttpClientPlugin<R> 
httpClientPlugin) {
-        this.httpClientPlugin = httpClientPlugin;
-    }
-
-    /**
-     * Custom retry policy.
-     *
-     * @param response   he Mono object of the response
-     * @param exchange   Current Server Exchange Object
-     * @param duration   Timeout
-     * @param retryTimes Number of retries
-     * @return Response Mono object after retry processing
-     */
-    public Mono<R> execute(final Mono<R> response, final ServerWebExchange 
exchange, final Duration duration, final int retryTimes) {
-        return null;
-    }
-}
diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
index 3826a7ccd7..cffa736a3a 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
@@ -23,6 +23,7 @@ import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.dto.convert.rule.impl.DivideRuleHandle;
+import org.apache.shenyu.common.enums.HttpRetryBackoffSpecEnum;
 import org.apache.shenyu.common.enums.LoadBalanceEnum;
 import org.apache.shenyu.common.enums.PluginEnum;
 import org.apache.shenyu.common.enums.RetryEnum;
@@ -125,6 +126,7 @@ public class DividePlugin extends AbstractShenyuPlugin {
         exchange.getAttributes().put(Constants.HTTP_TIME_OUT, 
ruleHandle.getTimeout());
         exchange.getAttributes().put(Constants.HTTP_RETRY, 
ruleHandle.getRetry());
         // set retry strategy stuff
+        exchange.getAttributes().put(Constants.HTTP_RETRY_BACK_OFF_SPEC, 
StringUtils.defaultIfEmpty(ruleHandle.getRetryBackOffSpec(), 
HttpRetryBackoffSpecEnum.getDefault()));
         exchange.getAttributes().put(Constants.RETRY_STRATEGY, 
StringUtils.defaultIfEmpty(ruleHandle.getRetryStrategy(), 
RetryEnum.CURRENT.getName()));
         exchange.getAttributes().put(Constants.LOAD_BALANCE, 
StringUtils.defaultIfEmpty(ruleHandle.getLoadBalance(), 
LoadBalanceEnum.RANDOM.getName()));
         exchange.getAttributes().put(Constants.DIVIDE_SELECTOR_ID, 
selector.getId());
diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
index 04b44d7fc8..d1b73b0808 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
@@ -24,6 +24,7 @@ import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.dto.convert.rule.impl.DivideRuleHandle;
 import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.enums.HttpRetryBackoffSpecEnum;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.UpstreamCheckUtils;
@@ -89,6 +90,8 @@ public final class DividePluginTest {
 
     private DiscoverySyncData discoverySyncData;
 
+    private DivideUpstreamDataHandler divideUpstreamDataHandler;
+
     private ServerWebExchange exchange;
 
     private ServerWebExchange postExchange;
@@ -178,6 +181,33 @@ public final class DividePluginTest {
         StepVerifier.create(result).expectSubscription().verifyComplete();
     }
 
+    @Test
+    public void testRetryBackOffSpecAttributeSet() {
+        DivideRuleHandle handle = new DivideRuleHandle();
+        
handle.setRetryBackOffSpec(HttpRetryBackoffSpecEnum.FIXED_BACKOFF.getName());
+        
when(ruleData.getHandle()).thenReturn(GsonUtils.getGson().toJson(handle));
+        DividePluginDataHandler dividePluginDataHandler = new 
DividePluginDataHandler();
+        dividePluginDataHandler.handlerRule(ruleData);
+        dividePluginDataHandler.handlerSelector(selectorData);
+        
divideUpstreamDataHandler.handlerDiscoveryUpstreamData(discoverySyncData);
+        when(chain.execute(exchange)).thenReturn(Mono.empty());
+        dividePlugin.doExecute(exchange, chain, selectorData, ruleData);
+        assertEquals(HttpRetryBackoffSpecEnum.FIXED_BACKOFF.getName(), 
exchange.getAttribute(Constants.HTTP_RETRY_BACK_OFF_SPEC));
+    }
+
+    @Test
+    public void testRetryBackOffSpecDefaultAttribute() {
+        DivideRuleHandle handle = new DivideRuleHandle();
+        
when(ruleData.getHandle()).thenReturn(GsonUtils.getGson().toJson(handle));
+        DividePluginDataHandler dividePluginDataHandler = new 
DividePluginDataHandler();
+        dividePluginDataHandler.handlerRule(ruleData);
+        dividePluginDataHandler.handlerSelector(selectorData);
+        
divideUpstreamDataHandler.handlerDiscoveryUpstreamData(discoverySyncData);
+        when(chain.execute(exchange)).thenReturn(Mono.empty());
+        dividePlugin.doExecute(exchange, chain, selectorData, ruleData);
+        assertEquals(HttpRetryBackoffSpecEnum.getDefault(), 
exchange.getAttribute(Constants.HTTP_RETRY_BACK_OFF_SPEC));
+    }
+
     /**
      * Skip.
      */
@@ -255,7 +285,7 @@ public final class DividePluginTest {
         
when(discoverySyncData.getUpstreamDataList()).thenReturn(divideUpstreamList);
         when(discoverySyncData.getSelectorId()).thenReturn("mock");
         DividePluginDataHandler dividePluginDataHandler = new 
DividePluginDataHandler();
-        DivideUpstreamDataHandler divideUpstreamDataHandler = new 
DivideUpstreamDataHandler();
+        divideUpstreamDataHandler = new DivideUpstreamDataHandler();
         dividePluginDataHandler.handlerRule(ruleData);
         dividePluginDataHandler.handlerSelector(selectorData);
         
divideUpstreamDataHandler.handlerDiscoveryUpstreamData(discoverySyncData);

Reply via email to