AlinsRan opened a new pull request, #13899:
URL: https://github.com/apache/apisix/pull/13899
### Description
`/v1/healthcheck` only walks `checks` on upstreams (`value.checks` /
`value.upstream.checks`), so a route whose real upstreams are LLM instances
configured on `ai-proxy-multi` reports no health state at all — the very state
the plugin consults when it skips an unhealthy instance. A monitoring system
polling the control API sees those instances as unchecked.
`ai-proxy-multi` keys each instance checker by `<resource
key>#plugins['ai-proxy-multi'].instances[<i>]`, a layout nothing outside the
plugin can guess. Rather than hard-coding it in the control API, a plugin now
declares its own checkers:
- `apisix/plugins/ai-proxy-multi.lua` — new `list_healthcheck_targets(conf,
resource_key)`, returning each checker's resource path, its `checks` and an
opaque `meta`. The path built in `pick_target()` is extracted into
`instance_resource_path()` and shared, so the checker identity has one
definition.
- `apisix/control/v1.lua` — `iter_and_add_healthcheck_info()` additionally
asks each configured plugin for its checkers; node lookup is factored into
`get_checker_nodes()` so both entry kinds read the same shm.
A plugin entry keeps the shape of an upstream entry and adds two fields:
```json
{
"name": "/apisix/routes/1#plugins['ai-proxy-multi'].instances[0]",
"plugin": "ai-proxy-multi",
"meta": {"instance": "openai"},
"type": "http",
"nodes": [
{"ip": "52.86.68.46", "port": 443, "status": "healthy",
"counter": {"success": 2, "http_failure": 0, "tcp_failure": 0,
"timeout_failure": 0}}
]
}
```
`meta` is filled by the plugin and reported verbatim — what a checker stands
for is the plugin's business, so the control API does not know what an instance
is.
### New sub-resource: `GET /v1/healthcheck/{src_type}/{src_id}/checkers`
One resource can now own several checkers — its upstream plus one per plugin
instance — which `/v1/healthcheck/{src_type}/{src_id}` cannot express: it
returns a single object, and a route whose upstreams live on `ai-proxy-multi`
answers `404 {"error_msg":"no checker for routes[1]"}` there, because its
upstream declares no `checks`.
The sub-resource returns all of them, as an array of the same entries the
listing uses, so a client parses one entry shape for both:
```json
GET /v1/healthcheck/routes/1/checkers
[
{"name": "/apisix/routes/1", "type": "http", "nodes": [...]},
{"name": "/apisix/routes/1#plugins['ai-proxy-multi'].instances[0]",
"plugin": "ai-proxy-multi", "meta": {"instance": "openai"},
"type": "http", "nodes": [...]}
]
```
- The existing single-object endpoint is untouched.
- A resource with no health check at all is not an error here — it owns an
empty set, serialized as `[]` (`array_mt`, so never `{}`).
- `404` only when the resource itself is missing, `400` for an unknown
sub-resource.
- HTML rendering (`Accept: text/html`) works the same way as on the other
two endpoints.
Docs updated in `docs/en/latest/control-api.md`.
### Which issue(s) this PR fixes
None filed; reported by a user whose monitoring platform polls
`/v1/healthcheck` and cannot see the health of LLM upstreams behind
`ai-proxy-multi`.
### Checklist
- [x] I have explained the need for this PR and the problem it solves
- [x] I have explained the changes or the new features added to this PR
- [x] I have added tests corresponding to this change
- [x] I have updated the documentation to reflect this change
- [x] I have verified that this change is backward compatible
### Notes
- `upstreams` cannot carry plugins (`schema_def.upstream` has no `plugins`
field), so their entries never gain a `plugin` field and their `checkers` set
holds at most one element.
- A single-instance `ai-proxy-multi` config never creates a checker, because
`pick_ai_instance()` short-circuits `pick_target()`; its entry is therefore
listed with an empty node list. Pre-existing plugin behaviour, untouched here.
- A plugin reaching a route through a `plugin_config` is not covered, since
that merge happens per request; the endpoint does not walk plugin configs today
either.
### Testing
New `t/control/healthcheck-ai-proxy-multi.t`, 8 cases: instance health
reported as `healthy`/`unhealthy`; plugin and upstream checkers coexisting in
one listing; `disable_upstream_healthcheck` leaving every node list unprobed;
instances listed before any probe; the `checkers` sub-resource on an AI route
and on a plain upstream route; and its empty-set / `404` / `400` paths.
All 24 assertions pass locally, as does `t/control/healthcheck.t`. Locally
the AI cases need `plugin_attr.ai-proxy.http_client: lua-resty-http`, because
this box has no `ngx_http_ffi_client` C module — the committed file uses the
default client, and the existing `t/plugin/ai-proxy-multi-*.t` files fail here
for the same reason, on master as well as on this branch.
--
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]