You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by GitBox <gi...@apache.org> on 2021/11/10 08:28:12 UTC

[GitHub] [apisix] chzhuo commented on issue #4077: passive healthcheck not working after configuration changing

chzhuo commented on issue #4077:
URL: https://github.com/apache/apisix/issues/4077#issuecomment-964890775


   > @Ben0625 Could you try the `2.5` version? And test it whether it can be reproduced in `2.5`?
   
   We get the same problems on the apisix 2.8  
     
   I found a bug in https://github.com/api7/lua-resty-healthcheck/blob/master/lib/resty/healthcheck.lua
   The content of var `defaults`  will be modified when not assigned the passive or active config item
   
   Reproduce the bug:
   nginx.conf
   ```lua
   daemon off;
   worker_processes  1;
   error_log stderr;
   events {
       worker_connections 1024;
   }
   http {
       access_log off;
       server {
           listen 19000;
           location / {
               default_type text/html;
               content_by_lua '
                   ngx.say("<p>Hello, World!</p>")
               ';
               log_by_lua '
                   local check = require("check")
               ';
           }
       }
   }
   
   ```
   check.lua
   ```lua
   local cjson = require("cjson.safe")
   
   -- copy from: https://github.com/api7/lua-resty-healthcheck/blob/master/lib/resty/healthcheck.lua#L1162
   --============================================================================
   -- Create health-checkers
   --============================================================================
   
   
   local NO_DEFAULT = {}
   local MAXNUM = 2^31 - 1
   
   
   local function fail(ctx, k, msg)
     ctx[#ctx + 1] = k
     error(table.concat(ctx, ".") .. ": " .. msg, #ctx + 1)
   end
   
   
   local function fill_in_settings(opts, defaults, ctx)
     ctx = ctx or {}
     local obj = {}
     for k, default in pairs(defaults) do
       local v = opts[k]
   
       -- basic type-check of configuration
       if default ~= NO_DEFAULT
       and v ~= nil
       and type(v) ~= type(default) then
         fail(ctx, k, "invalid value")
       end
   
       if v ~= nil then
         if type(v) == "table" then
           if default[1] then -- do not recurse on arrays
             obj[k] = v
           else
             ctx[#ctx + 1] = k
             obj[k] = fill_in_settings(v, default, ctx)
             ctx[#ctx + 1] = nil
           end
         else
           if type(v) == "number" and (v < 0 or v > MAXNUM) then
             fail(ctx, k, "must be between 0 and " .. MAXNUM)
           end
           obj[k] = v
         end
       elseif default ~= NO_DEFAULT then
         obj[k] = default
       end
   
     end
     return obj
   end
   
   
   local defaults = {
     name = NO_DEFAULT,
     shm_name = NO_DEFAULT,
     type = NO_DEFAULT,
     status_ver = 0,
     checks = {
       active = {
         type = "http",
         timeout = 1,
         concurrency = 10,
         http_path = "/",
         https_verify_certificate = true,
         healthy = {
           interval = 0, -- 0 = disabled by default
           http_statuses = { 200, 302 },
           successes = 2,
         },
         unhealthy = {
           interval = 0, -- 0 = disabled by default
           http_statuses = { 429, 404,
                             500, 501, 502, 503, 504, 505 },
           tcp_failures = 2,
           timeouts = 3,
           http_failures = 5,
         },
         req_headers = {""},
       },
       passive = {
         type = "http",
         healthy = {
           http_statuses = { 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
                             300, 301, 302, 303, 304, 305, 306, 307, 308 },
           successes = 5,
         },
         unhealthy = {
           http_statuses = { 429, 500, 503 },
           tcp_failures = 2,
           timeouts = 7,
           http_failures = 5,
         },
       },
     },
   }
   
   
   local function to_set(tbl, key)
     local set = {}
     for _, item in ipairs(tbl[key]) do
       set[item] = true
     end
     tbl[key] = set
   end
   
   
     -- In the below is my code
   local option_no_passive  =  cjson.decode([[
       {
           "checks":
           {
               "active":{"unhealthy":{"tcp_Failures":3,"http_statuses":[500,501,502,503,504,505],"timeouts":3,"interval":100,"tcp_failures":2,"http_failures":3},"concurrency":10,"http_path":"\/healthz","https_verify_certificate":true,"port":9080,"type":"http","healthy":{"interval":5,"successes":1,"http_statuses":[200,201,202,203,204,205,206,207,208,226,300,301,302,303,304,305,306,307,308,400,401,403,404,405,415,429]},"host":"healthcheck","timeout":5}
           },
           "name":"upstream#\/internal-apisix\/upstreams\/380542682478412600","shm_name":"upstream-healthcheck"
       }]])
   -- The default can be encoded to json
   ngx.log(ngx.ERR, "===defaults: ", cjson.encode(defaults))
   
   -- The default `passive` config will be filled into `filled_option_no_passive` by the method `fill_in_settings`
   local filled_option_no_passive = fill_in_settings(option_no_passive ,defaults)
   ngx.log(ngx.ERR, "===filled_option_no_passive: ", cjson.encode(filled_option_no_passive))
   
   -- copy from: https://github.com/api7/lua-resty-healthcheck/blob/master/lib/resty/healthcheck.lua#L1364
   to_set(filled_option_no_passive.checks.active.unhealthy, "http_statuses")
   to_set(filled_option_no_passive.checks.active.healthy, "http_statuses")
   to_set(filled_option_no_passive.checks.passive.unhealthy, "http_statuses")
   to_set(filled_option_no_passive.checks.passive.healthy, "http_statuses")
   
   -- print: nil Cannot serialise table: excessively sparse array while logging request
   -- The defaults has been modified by `to_set`
   ngx.log(ngx.ERR, "===defaults: ", cjson.encode(defaults))
   
   ```
   
   


-- 
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: notifications-unsubscribe@apisix.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org