Service
Event Hubs (admin/health plane)
API Action / Feature
GET /{account}-eventhub/health
What happens
The endpoint probes the configured amqp-port / amqp-tls-port rather than the ports the default namespace is actually listening on, so a namespace started with dynamic ports reports 503 while its broker is running.
$ curl -X PUT .../devstoreaccount1-eventhub/namespaces/emulatorNs1 \
-H 'Content-Type: application/json' -d '{"amqpPort":0,"amqpTlsPort":0}'
{"name":"emulatorNs1","amqpPort":52136,"amqpsPort":52137,"mocked":false}
$ curl -i .../devstoreaccount1-eventhub/health
HTTP/1.1 503
{"amqp":{"port":5672,"status":"down"},"amqps":{"port":5671,"status":"down"},"kafka":{"running":false}}
$ nc -z localhost 52136 && echo open
open # the broker is up, on the port the PUT returned
Why it is a bug rather than a design choice
docs/services/event-hub.md states the contract as:
Returns 200 when the default namespace AMQP broker is reachable, 503 otherwise
and, a few lines above, documents dynamic namespace ports as supported:
To use the dynamic namespace port, construct the connection string with the port explicitly: Endpoint=sb://localhost:47123;...
So the endpoint contradicts its own documented behaviour in a documented scenario.
Cause
EventHubHandler.handleHealth() reads the configuration:
int amqpPort = config.services().eventHub().amqpPort();
boolean amqpUp = isTcpOpen("localhost", amqpPort);
while the running namespace's real ports are on NamespaceState.amqpHostPort() / amqpsHostPort(), which appendNamespaceJson already reports from the namespace endpoints.
Ports only go dynamic when a caller explicitly sends amqpPort: 0 in the PUT body — they default to the configured values — so the default path is unaffected.
Not a regression, and newly visible
handleHealth() is unchanged on main and by #241 / #242 / #246. It was previously unobservable: with event-hub.mocked: true the create path returns before any broker starts, so the endpoint answered 503 unconditionally. #246 starts a real broker by default, which is what makes the remaining gap visible. Greptile flagged it while reviewing that PR; I reproduced it as above.
A question before a fix
The obvious fix is to probe the default namespace's NamespaceState ports when it is running and fall back to the configured ones otherwise, which restores the documented contract with no change to the response shape.
What is less obvious is what the endpoint should say once several namespaces run on different port pairs, since the body carries a single pair:
{"amqp":{"port":5672,"status":"up"},"amqps":{"port":5671,"status":"up"},"kafka":{"running":false}}
Options seem to be: keep it as "the default namespace" and leave it at that (smallest change, matches the docs); or add a per-namespace breakdown alongside the existing fields. That is a contract call rather than a bug fix, so I would rather ask than guess.
Happy to raise a PR for whichever shape you prefer — the narrow default-namespace version is a few lines.
Service
Event Hubs (admin/health plane)
API Action / Feature
GET /{account}-eventhub/healthWhat happens
The endpoint probes the configured
amqp-port/amqp-tls-portrather than the ports the default namespace is actually listening on, so a namespace started with dynamic ports reports503while its broker is running.Why it is a bug rather than a design choice
docs/services/event-hub.mdstates the contract as:and, a few lines above, documents dynamic namespace ports as supported:
So the endpoint contradicts its own documented behaviour in a documented scenario.
Cause
EventHubHandler.handleHealth()reads the configuration:while the running namespace's real ports are on
NamespaceState.amqpHostPort()/amqpsHostPort(), whichappendNamespaceJsonalready reports from the namespace endpoints.Ports only go dynamic when a caller explicitly sends
amqpPort: 0in thePUTbody — they default to the configured values — so the default path is unaffected.Not a regression, and newly visible
handleHealth()is unchanged onmainand by #241 / #242 / #246. It was previously unobservable: withevent-hub.mocked: truethe create path returns before any broker starts, so the endpoint answered503unconditionally. #246 starts a real broker by default, which is what makes the remaining gap visible. Greptile flagged it while reviewing that PR; I reproduced it as above.A question before a fix
The obvious fix is to probe the default namespace's
NamespaceStateports when it is running and fall back to the configured ones otherwise, which restores the documented contract with no change to the response shape.What is less obvious is what the endpoint should say once several namespaces run on different port pairs, since the body carries a single pair:
{"amqp":{"port":5672,"status":"up"},"amqps":{"port":5671,"status":"up"},"kafka":{"running":false}}Options seem to be: keep it as "the default namespace" and leave it at that (smallest change, matches the docs); or add a per-namespace breakdown alongside the existing fields. That is a contract call rather than a bug fix, so I would rather ask than guess.
Happy to raise a PR for whichever shape you prefer — the narrow default-namespace version is a few lines.