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

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


The following commit(s) were added to refs/heads/master by this push:
     new 89c782ee2 fix(etcd): do not block writes when the deployment role 
cannot be read (#13885)
89c782ee2 is described below

commit 89c782ee2e7b04e3f0ed3b6818ebc10281e561e4
Author: AlinsRan <[email protected]>
AuthorDate: Thu Aug 27 16:22:59 2026 +0800

    fix(etcd): do not block writes when the deployment role cannot be read 
(#13885)
---
 apisix/core/etcd.lua | 12 +++++--
 t/core/etcd-write.t  | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/apisix/core/etcd.lua b/apisix/core/etcd.lua
index 09a6b45f4..0845a5669 100644
--- a/apisix/core/etcd.lua
+++ b/apisix/core/etcd.lua
@@ -50,7 +50,7 @@ local function is_data_plane()
 
     local role = try_read_attr(local_conf, "deployment", "role")
     if role == "data_plane" then
-      return true
+        return true
     end
 
     return false
@@ -62,7 +62,9 @@ local function disable_write_if_data_plane()
     local data_plane, err = is_data_plane()
     if err then
         log.error("failed to check data plane role: ", err)
-        return true, err
+        -- the guard only warns for now, so failing to read the local config
+        -- must not be stricter than a confirmed data plane role
+        return false, err
     end
 
     if data_plane then
@@ -144,7 +146,11 @@ local function _new(etcd_conf)
         return nil, nil, err
     end
 
-    etcd_cli = wrap_etcd_client(etcd_cli)
+    local wrap_err
+    etcd_cli, wrap_err = wrap_etcd_client(etcd_cli)
+    if not etcd_cli then
+        return nil, nil, wrap_err
+    end
 
     return etcd_cli, prefix
 end
diff --git a/t/core/etcd-write.t b/t/core/etcd-write.t
index 457cb76ed..8d70b6726 100644
--- a/t/core/etcd-write.t
+++ b/t/core/etcd-write.t
@@ -1105,3 +1105,102 @@ deployment:
 GET /t
 --- no_error_log
 Data plane role should not write to etcd. This operation will be deprecated in 
future releases.
+
+
+
+=== TEST 34: an unreadable local config does not block the write
+--- yaml_config
+deployment:
+  role: control_plane
+  role_control_plane:
+    config_provider: etcd
+  etcd:
+    host:
+      - "http://127.0.0.1:2379";
+    prefix: "/apisix"
+    tls:
+      verify: false
+--- config
+    location /t {
+        content_by_lua_block {
+            local config_local = require("apisix.core.config_local")
+            local origin_local_conf = config_local.local_conf
+            local fail = false
+            config_local.local_conf = function(...)
+                if fail then
+                    return nil, "mocked local conf failure"
+                end
+                return origin_local_conf(...)
+            end
+
+            -- reload so that the module picks up the patched local_conf
+            package.loaded["apisix.core.etcd"] = nil
+            local etcd = require("apisix.core.etcd")
+
+            -- the first write caches the etcd client
+            local res, err = etcd.set("/foo", "bar")
+            if not res then
+                ngx.say("first set failed: ", err)
+                return
+            end
+
+            fail = true
+            res, err = etcd.set("/foo", "bar")
+            ngx.say("second set: ", res and "ok" or ("failed: " .. (err or 
"nil")))
+
+            fail = false
+            etcd.delete("/foo")
+            config_local.local_conf = origin_local_conf
+            package.loaded["apisix.core.etcd"] = nil
+        }
+    }
+--- request
+GET /t
+--- response_body
+second set: ok
+--- error_log
+failed to check data plane role: mocked local conf failure
+--- no_error_log
+Data plane role should not write to etcd. This operation will be deprecated in 
future releases.
+
+
+
+=== TEST 35: a client missing a wrapped method reports the reason
+--- yaml_config
+deployment:
+  role: control_plane
+  role_control_plane:
+    config_provider: etcd
+  etcd:
+    host:
+      - "http://127.0.0.1:2379";
+    prefix: "/apisix"
+    tls:
+      verify: false
+--- config
+    location /t {
+        content_by_lua_block {
+            local origin_etcd = package.loaded["resty.etcd"]
+            package.loaded["resty.etcd"] = {
+                new = function()
+                    -- every other wrapped method is missing
+                    return {set = function() end}
+                end,
+            }
+
+            package.loaded["apisix.core.etcd"] = nil
+            local etcd = require("apisix.core.etcd")
+
+            local res, err = etcd.set("/foo", "bar")
+            ngx.say("res: ", res and "ok" or "nil", ", err: ", err or "nil")
+
+            package.loaded["resty.etcd"] = origin_etcd
+            package.loaded["apisix.core.etcd"] = nil
+        }
+    }
+--- request
+GET /t
+--- response_body
+res: nil, err: method setnx not found in etcd client
+--- error_log
+method setnx not found in etcd client

Reply via email to