AlinsRan commented on code in PR #13855:
URL: https://github.com/apache/apisix/pull/13855#discussion_r3869707719


##########
apisix/admin/standalone.lua:
##########
@@ -343,9 +346,12 @@ function _M.init_worker()
                 end
             else
                 local last_modified = config[METADATA_LAST_MODIFIED]
-                if last_modified_per_worker ~= last_modified then
+                local digest = config[METADATA_DIGEST]
+                if last_modified_per_worker ~= last_modified
+                   or digest_per_worker ~= digest then
                     update_config(config)

Review Comment:
   Fair point — the digest comparison is the half that makes the worker 
recover, and nothing in the test touches it. TEST 1 only covers the 
`ip_port.lua` crash.
   
   On the shape though: the two fields are not symmetric, so the scenario as 
described cannot be produced deterministically from a test. `X-Digest` is the 
client header, but `X-Last-Modified` is server-generated 
(`apisix_yaml[METADATA_LAST_MODIFIED] = ngx_time()`), so to get two pushes with 
the same timestamp both have to land inside one second *and* the poll has to 
run between them. That is a race in both directions — it can pass with the fix 
reverted and fail with it in place.
   
   What I think is deterministic: write the second config straight into the 
`standalone-config` shared dict, keeping the timestamp, changing only the 
digest and the content, and posting no event — the polling loop is then the 
only thing that can deliver it. Something like:
   
   ```lua
   local dict = ngx.shared["standalone-config"]
   local stored = core.json.decode(dict:get("config"))
   stored["X-Digest"] = "changed"
   stored.routes_conf_version = stored.routes_conf_version + 1  -- update() 
bumps this on every push
   stored.routes = { { id = "r2", uri = "/r2", upstream = ... } }
   dict:set("config", core.json.encode(stored))
   ```
   
   with one poll interval allowed to pass first, so the worker has recorded the 
previous timestamp — otherwise the second config is its first observation and 
would be applied even without the fix.
   
   I have not pushed that test yet: I could not get it to pass locally even 
with the fix in place, and I do not want to add a test I have not seen work. 
The route pushed in the preceding block was not reachable in my runs, which 
looks like a local harness/events problem rather than the code, so I would 
rather resolve that first than guess. Will follow up.
   
   Two things worth recording while this is open:
   
   - Comparing both fields rather than the digest alone is deliberate. The 
digest is client-supplied and a client may reuse one for different content; 
keeping the timestamp in the comparison is the conservative side.
   - "Same digest, different content" cannot reach the poll loop at all: 
`update()` answers 204 and stores nothing when the digest matches, so that 
combination never gets written.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to