shreemaan-abhishek commented on code in PR #13778:
URL: https://github.com/apache/apisix/pull/13778#discussion_r3748009598
##########
apisix/plugins/ai-transport/http.lua:
##########
@@ -19,17 +19,131 @@
-- Provides HTTP client lifecycle management for AI provider requests.
local core = require("apisix.core")
-local http = require("resty.http")
local ngx_now = ngx.now
local pairs = pairs
local ipairs = ipairs
local pcall = pcall
+local require = require
local type = type
local str_lower = string.lower
+local tonumber = tonumber
local tostring = tostring
+local FFI_CLIENT = "ngx_http_ffi_client"
+local LUA_RESTY_HTTP = "lua-resty-http"
+
+-- the client name in the config is not the module name
+local CLIENT_MODULES = {
+ [FFI_CLIENT] = "resty.ngx_http_ffi_client",
+ [LUA_RESTY_HTTP] = "resty.http",
+}
+
+local attr_schema = {
+ type = "object",
+ properties = {
+ http_client = {
+ type = "string",
+ enum = {FFI_CLIENT, LUA_RESTY_HTTP},
+ default = FFI_CLIENT,
+ },
+ },
+}
+
local _M = {}
+local http_client
+local http_client_is_ffi
+
+
+--- Pick the outbound HTTP client.
+-- `plugin_attr.ai-proxy.http_client` names it: "ngx_http_ffi_client", the
+-- default, or "lua-resty-http". The first is a C client with the same object
+-- API as the second and around half its outbound CPU cost, and it exists only
+-- when the gateway runtime was built with the module.
+-- Resolved on first request, because local_conf is not readable while the
+-- module is still loading, and cached only once a client has been loaded.
+local function resolve_client()
+ if http_client then
+ return http_client
+ end
+
+ local local_conf = core.config.local_conf()
+ local attr = core.table.try_read_attr(local_conf, "plugin_attr",
"ai-proxy") or {}
+
+ local ok, err = core.schema.check(attr_schema, attr)
+ if not ok then
+ core.log.error("invalid plugin_attr.ai-proxy: ", err)
+ return nil, "invalid plugin_attr.ai-proxy: " .. err
+ end
+
+ local name = attr.http_client or FFI_CLIENT
+ local module_name = CLIENT_MODULES[name]
+
+ local mod
+ ok, mod = pcall(require, module_name)
+ if not ok or type(mod) ~= "table" then
+ core.log.error(module_name, " is not available: ", mod)
+ return nil, module_name .. " is not available: " .. tostring(mod)
+ end
+
+ http_client = mod
+ http_client_is_ffi = name == FFI_CLIENT
+
+ return http_client
+end
Review Comment:
Good point, moved. The selection now lives in `apisix/utils/http.lua`, next
to the other shared client factories (`utils/redis.lua` is the closest
precedent), and `ai-transport/http.lua` is just a consumer.
The split keeps the reusable half in the shared module and the
plugin-specific half out of it:
- `utils/http.lua` owns the client names, a `client_schema` fragment callers
embed in their own attribute schema, loading and per-name caching, and
`resolve_upstream_host()`.
- the caller owns **where the preference comes from** and passes the name to
`new(name)`. So `ai-transport` reads `plugin_attr.ai-proxy.http_client`, and
forward-auth or http-logger can read their own key without inheriting an
AI-specific one.
`resolve_upstream_host()` is the part most worth sharing. `apisix/patch.lua`
wraps cosocket `connect` so hostnames go through `core.resolver`, which honours
`dns_resolver`, `/etc/hosts` and the search domains. A client that dials from C
never touches a cosocket and sees only nginx's `resolver`, so without this
every `localhost`-style upstream fails. Any plugin moving off lua-resty-http
will hit that, so it should not be reimplemented per plugin.
I deliberately did **not** introduce a global config key. Making
`http_client` gateway-wide is a user-facing decision that felt like yours to
make rather than something to slip into this PR; the shared module is agnostic,
so a global default can be added later without touching callers.
One option I skipped: having `new()` return a wrapper whose `connect()`
resolves transparently, so callers would not need the `needs_resolve()` check.
That removes a step for every future caller but adds a metatable indirection on
a per-request path, so I left it explicit. Happy to switch if you prefer it.
No behaviour change; `t/plugin/ai-transport-http.t` (61 subtests) plus
`ai-proxy.t`, `ai-proxy-multi.t`, `ai-request-rewrite.t` and
`ai-transport-header-forwarding.t` all pass unchanged.
--
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]