fatihbm commented on code in PR #13810: URL: https://github.com/apache/apisix/pull/13810#discussion_r3793004599
########## apisix/plugins/query-gateway/cache.lua: ########## @@ -0,0 +1,455 @@ +-- +-- 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. +-- +local core = require("apisix.core") +local redis = require("apisix.utils.redis") +local rediscluster = require("apisix.utils.rediscluster") +local resty_sha256 = require("resty.sha256") +local to_hex = require("resty.string").to_hex +local ngx = ngx + +local concat = table.concat +local lower = string.lower +local pairs = pairs +local ipairs = ipairs +local math_min = math.min +local table_sort = table.sort +local tonumber = tonumber + +local _M = {} + +local HOP_BY_HOP = { + connection = true, + ["keep-alive"] = true, + ["proxy-authenticate"] = true, + ["proxy-authorization"] = true, + te = true, + trailer = true, + ["transfer-encoding"] = true, + upgrade = true, +} + +local ALLOWED_VARY = { + accept = true, + ["accept-encoding"] = true, + ["accept-language"] = true, +} + +local function sha256_hex(value) + local sha256 = resty_sha256:new() + sha256:update(value) + return to_hex(sha256:final()) +end + +local function shared_dict() + return ngx.shared["query-gateway-cache"] +end + +local function cache_id(conf) + if conf.backend == "redis" then + return "redis:" .. conf.redis_host .. ":" .. (conf.redis_port or 6379) + end + + if conf.backend == "redis-cluster" then + return "redis-cluster:" .. conf.redis_cluster_name + end + + return "local" +end + +local function local_key(key) + return "entry:" .. key +end + +local function breaker_key(conf) + return "breaker:" .. cache_id(conf) +end + +local function use_fallback(conf) + if conf.backend == "local" then + return true + end + + return shared_dict():get(breaker_key(conf)) ~= nil +end + +local function mark_backend_failure(conf, err) + shared_dict():set(breaker_key(conf), true, conf.fallback_ttl) + core.log.warn("query-gateway cache backend unavailable: ", err, + "; using local memory for ", conf.fallback_ttl, " seconds") +end + +local function local_get(key) + return shared_dict():get(local_key(key)) +end + +local function local_set(key, value, ttl) + local ok, err = shared_dict():set(local_key(key), value, ttl) + if not ok then + core.log.warn("failed to store query cache entry locally: ", err) + end + return ok +end + +local function redis_get(conf, key) + local red, err = redis.new(conf) + if not red then + return nil, err + end + + local value + value, err = red:get(key) + local ok, keepalive_err = red:set_keepalive(conf.redis_keepalive_timeout or 10000, + conf.redis_keepalive_pool or 100) + if not ok then + core.log.warn("failed to set redis keepalive: ", keepalive_err) + end + + if value == ngx.null then + return nil + end + return value, err +end + +local function redis_set(conf, key, value, ttl) + local red, err = redis.new(conf) + if not red then + return nil, err + end + + local ok + ok, err = red:set(key, value, "EX", ttl) + local keepalive_ok, keepalive_err = red:set_keepalive(conf.redis_keepalive_timeout or 10000, + conf.redis_keepalive_pool or 100) + if not keepalive_ok then + core.log.warn("failed to set redis keepalive: ", keepalive_err) + end + return ok, err +end + +local function cluster_get(conf, key) + local red, err = rediscluster.new(conf, "query-gateway-redis-cluster-slot-lock") + if not red then + return nil, err + end + + local value + value, err = red:get(key) + if value == ngx.null then + return nil + end + return value, err +end + +local function cluster_set(conf, key, value, ttl) + local red, err = rediscluster.new(conf, "query-gateway-redis-cluster-slot-lock") + if not red then + return nil, err + end + + return red:set(key, value, "EX", ttl) +end + +local function backend_get(conf, key) + if use_fallback(conf) then + return local_get(key), nil, "local-fallback" + end + + if conf.backend == "local" then + return local_get(key), nil, "local" + end + + local value, err + if conf.backend == "redis" then + value, err = redis_get(conf, key) + else + value, err = cluster_get(conf, key) + end + + if err then + mark_backend_failure(conf, err) + return local_get(key), nil, "local-fallback" + end + + return value, nil, conf.backend +end + +local function backend_set(conf, key, value, ttl) + if use_fallback(conf) then + return local_set(key, value, conf.fallback_ttl) + end + + if conf.backend == "local" then + return local_set(key, value, ttl) + end + + local ok, err + if conf.backend == "redis" then + ok, err = redis_set(conf, key, value, ttl) + else + ok, err = cluster_set(conf, key, value, ttl) + end + + if not ok then + mark_backend_failure(conf, err) + return local_set(key, value, conf.fallback_ttl) + end + + return true +end + +local function has_directive(value, directive) + return value and ngx.re.find(lower(value), "(?:^|,)\\s*" .. directive .. "(?:\\s|,|=|$)", "jo") Review Comment: Fixed in the follow-up commit. The directive checks now use valid PCRE patterns, and regression coverage was added for request and response Cache-Control: no-store / no-cache. -- 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]
