Connections
A connection is a typed, reusable resource that connects Hantera to an external broker or messaging service. One connection definition carries the endpoint, the credentials, and the recovery policy — so ingresses and egresses reference the connection by id and never see the credentials themselves.
AMQP 1.0 is the initial shared protocol. The connection's type identifies the external service and its semantics, while the ingress type (queue or stream) identifies the delivery behavior on top of it:
| Type | What it connects to | Delivery |
|---|---|---|
rabbitmq | RabbitMQ 4.x (AMQP 1.0 is core in 4.x) | Queue ingress, egress send |
azureServiceBus | Azure Service Bus namespaces | Queue ingress (queue/topic entities), egress send |
azureEventHubs | Azure Event Hubs namespaces | Stream ingress, egress send |
Defining a connection
A connection can be created through the HTTP API, applied as a CLI manifest file, or declared in an app's manifest — whichever fits how you work:
PUT /resources/connections/partner-rabbit
Content-Type: application/json{
"type": "rabbitmq",
"properties": {
"protocol": "amqp10",
"endpoint": "amqp://localhost:5672",
"authentication": {
"mechanism": "plain",
"username": "integration",
"password": "secret"
},
"reconnect": {
"initialDelaySeconds": 1,
"maxDelaySeconds": 60
}
}
}The complete definition is replaced on every PUT.
Configuring an app-provided connection per tenant
The literal values in an app manifest are defaults. To let each tenant's administrator configure the endpoint or credentials without shipping a new app version, bind those fields to app settings:
# h_app.yaml
connections:
partner-rabbit:
type: rabbitmq
properties:
protocol: amqp10
endpoint: amqp://localhost:5672 # default until the setting is configured
authentication:
mechanism: plain
username: integration
settings:
amqpEndpoint:
label:
default: AMQP endpoint
bindings:
connections:
partner-rabbit: $.properties.endpoint
amqpPassword:
label:
default: AMQP password
secret: true
bindings:
connections:
partner-rabbit: $.properties.authentication.passwordA configured setting overlays its bound field on the effective connection (reads and the connection runtime both see it); an unset setting leaves the literal default. Mark credential settings secret: true — the resolved value never appears in resource reads or logs. See Settings Bindings for the full model.
Properties
| Property | Required | Description |
|---|---|---|
protocol | Yes | Must be amqp10. |
endpoint | Yes | Absolute amqp:// or amqps:// URI with a host. |
authentication | Yes for most types | Authentication material; the shape depends on the mechanism (below). |
reconnect.initialDelaySeconds | No | First reconnect delay after a dropped connection (default 1). |
reconnect.maxDelaySeconds | No | Ceiling for the exponential back-off (default 60). |
traceContext.receive | No | Set to ignore to discard trace metadata carried by incoming messages (see Trace propagation). |
Authentication mechanisms
RabbitMQ — SASL PLAIN:
authentication:
mechanism: plain
username: integration
password: secretAzure Service Bus and Azure Event Hubs — claims-based security (CBS) with a SAS policy. Accept either a full connection string or the policy name and key directly:
authentication:
sharedAccessKeyName: send-listen
sharedAccessKey: SGVsbG8=authentication:
connectionString: Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=send-listen;SharedAccessKey=SGVsbG8=For local testing against the Azure Event Hubs emulator, which accepts unauthenticated AMQP and does not implement CBS, use the anonymous mechanism instead:
authentication:
mechanism: anonymousmechanism defaults to cbs for the Azure types. Anything other than cbs or anonymous is rejected with guidance.
WARNING
Credentials are secrets. They are validated by the adapter at write time and never appear in signals, audit records, traffic captures, or dev-session output. Store the values through the registry's secret mechanisms or your deployment pipeline rather than committing them.
Connection status
The platform reconciles each connection definition into a live transport and monitors it. A connection's status is distinct from its definition:
GET /resources/connections/{id}The response always includes a status object:
{
"id": "partner-rabbit",
"type": "rabbitmq",
"properties": { "protocol": "amqp10", "endpoint": "amqp://localhost:5672" },
"status": {
"state": "active",
"lastReconciledAt": "2026-09-20T10:12:35Z",
"health": { "healthy": true }
}
}| State | Meaning |
|---|---|
starting | No transport yet — the first reconcile has not completed. |
active | A transport is established and ready. |
failed | No active transport: reconcile failed and no last-known-good definition exists. |
To include status on list responses, add ?status=true:
GET /resources/connections?status=trueA definition update that fails validation or cannot connect keeps the previous transport serving traffic (last-known-good) — a re-serialized but identical definition never churns the connection.
Status signals
Connection state is also published as transient registry signals, so portals and monitoring can subscribe without polling:
signals/connections/{id}/status— an informational, non-issue status signal while the connection is active.signals/connections/{id}/reconciliation— an error signal when a connection cannot be established, carrying the failure reason.
Signals are read through the registry like any other signal entry.
Collisions
Two queue ingresses on the same connection and address would compete for the same deliveries. Instead of double-consuming, the platform elects a single winner by priority and the contenders stay installed but inactive, with a warning signal on the losing ingress naming the winner. The same applies to stream ingresses, where the durable subscription id is part of the collision identity.
Egress sending through a connection
Components running inside an egress can send messages over a connection with the send macro — see Egresses: Sending over a connection. The egress resource's ACL grants the use of the connection with connections/{id}:use; callers never learn the address or the credentials.
Trace propagation
Outbound sends stamp the ambient trace onto the message, and messages consumed through a queue or stream ingress restore that trace — the ingress names the sending egress as its trace parent, connecting the two request rows across the broker.
Trace metadata from a remote producer is observability input, not authorization. Connections to untrusted partners can opt out with:
traceContext:
receive: ignoreAuthorization
Connections carry no ACL of their own — nothing executes under a connection. Access is decided by the standard permission system:
connections/{id}:read # View the connection definition and status
connections/{id}:write # Create, update, or delete the definition
connections/{id}:use # Granted inside an egress ACL: send through the connectionRelated
- Queue ingresses — consume messages over a connection
- Stream ingresses — consume event streams with checkpoints
- Egresses — the
sendmacro for outbound messages - Settings Bindings — configure app-provided connection fields per tenant