@@ -19,6 +19,10 @@ local core = require("apisix.core")
1919local schema = require (" apisix.plugins.ai-proxy.schema" )
2020local base = require (" apisix.plugins.ai-proxy.base" )
2121local plugin = require (" apisix.plugin" )
22+ local ipmatcher = require (" resty.ipmatcher" )
23+ local healthcheck_manager = require (" apisix.healthcheck_manager" )
24+ local tonumber = tonumber
25+ local pairs = pairs
2226
2327local require = require
2428local pcall = pcall
@@ -118,17 +122,100 @@ local function transform_instances(new_instances, instance)
118122 new_instances [instance .priority ][instance .name ] = instance .weight
119123end
120124
125+ local function parse_domain_for_node (node )
126+ local host = node .domain or node .host
127+ if not ipmatcher .parse_ipv4 (host )
128+ and not ipmatcher .parse_ipv6 (host )
129+ then
130+ node .domain = host
121131
122- local function create_server_picker (conf , ups_tab )
132+ local ip , err = core .resolver .parse_domain (host )
133+ if ip then
134+ node .host = ip
135+ end
136+
137+ if err then
138+ core .log .error (" dns resolver domain: " , host , " error: " , err )
139+ end
140+ end
141+ end
142+
143+
144+ local function resolve_endpoint (instance_conf )
145+ local endpoint = core .table .try_read_attr (instance_conf , " override" , " endpoint" )
146+ local scheme , host , port , _ = endpoint :match (" ^(https?)://([^:/]+):?(%d*)(/?.*)$" )
147+ if port == " " then
148+ port = (scheme == " https" ) and " 443" or " 80"
149+ end
150+ local node = {
151+ host = host ,
152+ port = tonumber (port ),
153+ scheme = scheme ,
154+ }
155+ parse_domain_for_node (node )
156+ return node
157+ end
158+
159+
160+ local function get_checkers_status_ver (checkers )
161+ local status_ver_total = 0
162+ for _ , checker in pairs (checkers ) do
163+ status_ver_total = status_ver_total + checker .status_ver
164+ end
165+ return status_ver_total
166+ end
167+
168+
169+
170+ local function fetch_health_instances (conf , checkers )
171+ local instances = conf .instances
172+ local new_instances = core .table .new (0 , # instances )
173+ if not checkers then
174+ for _ , ins in ipairs (conf .instances ) do
175+ transform_instances (new_instances , ins )
176+ end
177+ return new_instances
178+ end
179+
180+ for _ , ins in ipairs (instances ) do
181+ local checker = checkers [ins .name ]
182+ if checker then
183+ local host = ins .checks and ins .checks .active and ins .checks .active .host
184+ local port = ins .checks and ins .checks .active and ins .checks .active .port
185+
186+ local node = resolve_endpoint (ins )
187+ local ok , err = checker :get_target_status (node .host , port or node .port , host )
188+ if ok then
189+ transform_instances (new_instances , ins )
190+ elseif err then
191+ core .log .error (" failed to get health check target status, addr: " ,
192+ node .host , " :" , port or node .port , " , host: " , host , " , err: " , err )
193+ end
194+ else
195+ transform_instances (new_instances , ins )
196+ end
197+ end
198+
199+ if core .table .nkeys (new_instances ) == 0 then
200+ core .log .warn (" all upstream nodes is unhealthy, use default" )
201+ for _ , ins in ipairs (instances ) do
202+ transform_instances (new_instances , ins )
203+ end
204+ end
205+
206+ return new_instances
207+ end
208+
209+
210+ local function create_server_picker (conf , ups_tab , checkers )
123211 local picker = pickers [conf .balancer .algorithm ] -- nil check
124212 if not picker then
125213 pickers [conf .balancer .algorithm ] = require (" apisix.balancer." .. conf .balancer .algorithm )
126214 picker = pickers [conf .balancer .algorithm ]
127215 end
128- local new_instances = {}
129- for _ , ins in ipairs (conf .instances ) do
130- transform_instances (new_instances , ins )
131- end
216+
217+ local new_instances = fetch_health_instances (conf , checkers )
218+ core .log .info (" fetch health instances: " , core .json .delay_encode (new_instances ))
132219
133220 if # new_instances ._priority_index > 1 then
134221 core .log .info (" new instances: " , core .json .delay_encode (new_instances ))
@@ -149,11 +236,57 @@ local function get_instance_conf(instances, name)
149236end
150237
151238
239+ function _M .construct_upstream (instance )
240+ local upstream = {}
241+ local node = resolve_endpoint (instance )
242+ if not node then
243+ return nil , " failed to resolve endpoint for instance: " .. instance .name
244+ end
245+
246+ if not node .host or not node .port then
247+ return nil , " invalid upstream node: " .. core .json .encode (node )
248+ end
249+
250+ parse_domain_for_node (node )
251+
252+ local node = {
253+ host = node .host ,
254+ port = node .port ,
255+ scheme = node .scheme ,
256+ weight = instance .weight or 1 ,
257+ priority = instance .priority or 0 ,
258+ name = instance .name ,
259+ }
260+ upstream .nodes = {node }
261+ upstream .checks = instance .checks
262+ return upstream
263+ end
264+
265+
152266local function pick_target (ctx , conf , ups_tab )
267+ local checkers
268+ for i , instance in ipairs (conf .instances ) do
269+ if instance .checks then
270+ -- json path is 0 indexed so we need to decrement i
271+ local resource_path = conf ._meta .parent .resource_key ..
272+ " #plugins['ai-proxy-multi'].instances[" .. i - 1 .. " ]"
273+ local resource_version = conf ._meta .parent .resource_version
274+ local checker = healthcheck_manager .fetch_checker (resource_path , resource_version )
275+ checkers = checkers or {}
276+ checkers [instance .name ] = checker
277+ end
278+ end
279+
280+ local version = plugin .conf_version (conf )
281+ if checkers then
282+ local status_ver = get_checkers_status_ver (checkers )
283+ version = version .. " #" .. status_ver
284+ end
285+
153286 local server_picker = ctx .server_picker
154287 if not server_picker then
155- server_picker = lrucache_server_picker (ctx .matched_route .key , plugin . conf_version ( conf ) ,
156- create_server_picker , conf , ups_tab )
288+ server_picker = lrucache_server_picker (ctx .matched_route .key , version ,
289+ create_server_picker , conf , ups_tab , checkers )
157290 end
158291 if not server_picker then
159292 return nil , nil , " failed to fetch server picker"
0 commit comments