Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: perf fixes #4

Merged
merged 12 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 36 additions & 33 deletions kong/plugins/advanced-router/handler.lua
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
local inspect = require("inspect")
local inspect = require "inspect"
local cjson_safe = require "cjson.safe"
local url = require "socket.url"
local date = require "date"
local pl_tablex = require "pl.tablex"
local pl_utils = require "pl.utils"

local kong = kong

local get_io_data = require("kong.plugins.advanced-router.io").get_io_data
local extract = require("kong.plugins.advanced-router.utils").extract
local replaceStringEnvVariables = require("kong.plugins.advanced-router.utils").replaceStringEnvVariables
local build_url = require("kong.plugins.advanced-router.utils").build_url
local interpolate_string_env = require("kong.plugins.advanced-router.utils").interpolate_string_env

local AdvancedRouterHandler = {}

AdvancedRouterHandler.PRIORITY = tonumber((os.getenv("PRIORITY_ADVANCED_ROUTER")))
AdvancedRouterHandler.PRIORITY = tonumber(os.getenv("PRIORITY_ADVANCED_ROUTER"))
AdvancedRouterHandler.VERSION = "1.0.0"

local boolean_functions = {}

local kong_proxy_port

function get_poxy_port()
local http_listener = pl_tablex.filter(kong.configuration.proxy_listeners, function(x)
if not x.ssl then
return true
end
end)
return http_listener[1]['port']
end

function get_current_timestamp_utc()
return date.diff(date(true), date(1970, 1, 1)):spanseconds()
end
Expand All @@ -36,14 +25,15 @@ function get_timestamp_utc(date_string)
end

function extract_from_io_response(key)
return extract(key, kong.ctx.plugin.io_data)
return kong.ctx.plugin.io_data[key]
end

function generate_boolean_function(proposition)

if proposition['condition'] == 'default' then
return assert(loadstring("return " .. "\"" .. proposition["upstream_url"] .. "\""))
end
local upstream_url = build_url(proposition["upstream_url"], kong_proxy_port)
local upstream_url = proposition["upstream_url"]
return assert(loadstring("if " .. proposition["condition"] .. "then return " .. "\"" .. upstream_url .. "\"" .. " end"))
end

Expand All @@ -69,27 +59,20 @@ function get_upstream_url(conf)
break
end
end
return value
return interpolate_string_env(value)
end

function set_upstream(upstream_url)
local parsed_url = url.parse(upstream_url)
local scheme = parsed_url['scheme'] or 'http'
local host = parsed_url['host']
local path = parsed_url['path']
local port = tonumber(parsed_url['port']) or 80
kong.service.request.set_scheme(scheme)
kong.log.debug("Upstream URL::" .. inspect(upstream_url))
kong.log.debug("Parsed Upstream URL::" .. inspect(parsed_url))
kong.service.set_target(host, port)
kong.service.request.set_scheme(parsed_url['scheme'] or 'http')
kong.service.set_target(parsed_url['host'], tonumber(parsed_url['port']) or 80)
if path then
kong.service.request.set_path(path)
kong.service.request.set_path(parsed_url['path'])
end

end

function AdvancedRouterHandler:access(conf)
local io_data, err = get_io_data(pl_tablex.merge(conf, { kong_proxy_port = kong_proxy_port }, true))
local io_data, err = get_io_data(conf)
if err then
kong.log.err("Error in getting io data" .. inspect(err))
return kong.response.exit(500, { error = "Error in getting io data" .. inspect(err) })
Expand All @@ -100,12 +83,32 @@ function AdvancedRouterHandler:access(conf)
if not upstream_url then
return kong.response.exit(500, "Not able to resolve upstream in advanced router")
end
upstream_url = replaceStringEnvVariables(upstream_url, io_data)
set_upstream(upstream_url)
end

function AdvancedRouterHandler:init_worker()
kong_proxy_port = get_poxy_port()
kong.worker_events.register(
function(data)
if type(data) ~= "string" then
return
end

local key_parts = pl_utils.split(data, ":")
if key_parts[1] ~= "plugins" or key_parts[2] ~= "advanced-router" then
return
end
local route_id = key_parts[3]
kong.log.info("Invalidating boolean functions of route :: " .. route_id)
if boolean_functions[route_id] ~= nil then
boolean_functions[route_id] = nil
end
kong.log.info("Invalidating io_request_template of route :: " .. route_id)
kong.cache:invalidate('io_request_template' .. route_id, false)

end,
"mlcache",
"mlcache:invalidations:kong_core_db_cache"
)
end

return AdvancedRouterHandler
Expand Down
82 changes: 41 additions & 41 deletions kong/plugins/advanced-router/io.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
local http = require "resty.http"
local cjson_safe = require "cjson.safe"
local inspect = require "inspect"
local pl_utils = require "pl.utils"
local pl_tablex = require "pl.tablex"

local generate_signature_hash = require("kong.plugins.advanced-router.utils").generate_signature_hash
local kong = kong

local interpolate_string_env = require "kong.plugins.advanced-router.utils".interpolate_string_env
local extract = require "kong.plugins.advanced-router.utils".extract
local belongs = require "kong.plugins.advanced-router.utils".belongs
local replaceStringEnvVariables = require "kong.plugins.advanced-router.utils".replaceStringEnvVariables
local build_url = require("kong.plugins.advanced-router.utils").build_url

local _M = {}

Expand All @@ -23,17 +23,21 @@ end
function extract_from_request(object, key)
local value
if object == 'headers' then
value = extract(string.lower(key), kong.request.get_headers())
return value
value = kong.request.get_header(string.lower(key))
else
value = extract(key, kong.request.get_query())
return value
value = kong.request.get_query_arg(key)
end
return value
end

function get_io_request_template(conf)
return cjson_safe.decode(conf.io_request_template), nil, 3600
end

function extract_io_data_from_request(conf)
local io_request_template = cjson_safe.decode(conf.io_request_template)
local cache_key = 'io_request_template:' .. conf.route_id
local io_request_template = kong.cache:get(cache_key, {}, get_io_request_template, conf)

local io_req = {
headers = {},
query = {},
Expand All @@ -42,46 +46,33 @@ function extract_io_data_from_request(conf)
local req_parts = { "headers", "query", "body" }

-- This loop parses the io_request_template and populates each field from request data
for _, part in ipairs(req_parts) do
if io_request_template[part] then
for key, value in pairs(io_request_template[part]) do
local i = string.find(value, "%.")
if i then
local from_part = value:sub(1, i - 1)
if belongs(part, req_parts) then
io_req[part][key] = extract_from_request(from_part, value:sub(i + 1))
else
io_req[part][key] = value
end
for _, req_part in ipairs(req_parts) do
if io_request_template[req_part] then
-- Ex: req_part = headers, key = a, value = headers.a
for key, value in pairs(io_request_template[req_part]) do
local first_part, second_part = pl_utils.splitv(value, '%.')
if second_part and pl_tablex.find(req_parts, first_part) then
io_req[req_part][key] = extract_from_request(first_part, second_part)
else
io_req[part][key] = value
io_req[req_part][key] = value
end
end
end
end
return io_req
end

function get_cache_key(data)
local json_string = cjson_safe.encode(data)
local hash = generate_signature_hash(json_string)
return hash
end

function get_io_data_from_remote(request_data, conf)
kong.log.debug("Making io call::" .. inspect(request_data))
local client = get_http_client(conf)
request_data.headers["Content-Type"] = "application/json"
local res, err1 = client:request_uri(
request_data.io_url,
{
method = request_data.io_http_method,
headers = request_data.headers,
headers = pl_tablex.merge(request_data.headers, { ['Content-Type'] = 'application/json' }),
body = cjson_safe.encode(request_data.body),
query = request_data.query
}
)
kong.log.debug("IO call error::" .. inspect(err1))
if not res or err1 then
return nil, err1
end
Expand All @@ -92,22 +83,23 @@ function get_io_data_from_remote(request_data, conf)
if not bodyJson then
return nil, err2
end
kong.log.debug("Data from I/O::" .. inspect(bodyJson))
local cacheTTL
if conf.cache_io_response then
cacheTTL = res.headers[conf.cache_ttl_header] or conf["default_edge_ttl_sec"]
cacheTTL = res.headers[conf.cache_ttl_header] or conf["default_cache_ttl_sec"]
else
cacheTTL = -1
end

return bodyJson, nil, tonumber(cacheTTL)
local result = {}
for _, v in ipairs(conf.variables) do
result[v] = extract(v, bodyJson)
end
return result, nil, tonumber(cacheTTL)
end

function get_io_data(request_data, conf)
local cache_key = get_cache_key(request_data)
kong.log.debug("cache_key::" .. cache_key)
-- TODO: Check all options parameters
-- ttl values are overridden if callback returns ttl as third return value
local cache_key = request_data['cache_key']
-- These values are default ttl values if they are not returned from callback function
local options = {
ttl = 60,
neg_ttl = 60
Expand All @@ -122,9 +114,17 @@ end

function create_io_request(conf)
local io_request = extract_io_data_from_request(conf)
kong.log.debug("conf" .. inspect(conf))
io_request["io_url"] = build_url(replaceStringEnvVariables(conf.io_url), conf.kong_proxy_port)
local req_part, key = pl_utils.splitv(conf.cache_identifier, "%.")

local cache_identifier = extract_from_request(req_part, key)
if not cache_identifier then
return kong.response.exit(400, { error = "Cache identifier not found in request:: " .. conf.cache_identifier })
end

io_request["cache_key"] = conf.io_http_method .. ':' .. conf.io_url .. ':' .. cache_identifier
io_request["io_url"] = interpolate_string_env(conf.io_url)
io_request["io_http_method"] = conf.io_http_method

return io_request
end

Expand Down
Loading