Configuration
Every setting reads from the environment with the prefix
ACEMQ_ and __ between levels, and from a
.env file beside the process. They can also be written
down:
acemq = AceMQ() # from the environment
acemq = AceMQ(AceMQSettings(url="amqp://host:5672/")) # written down
acemq = AceMQ(settings.acemq) # nested in the app's own settingsAceMQSettings is a pydantic-settings model.
That is a dependency this package took deliberately: FastAPI already
brings pydantic, so what it adds is one small package whose whole job is
reading environment variables into a model — and the alternative is this
repository owning a parser for durations, nested keys and
.env files forever. The Spring starter does not write its
own binder either.
Durations accept a bare number of seconds
(30), ISO 8601 (PT30S) or
H:MM:SS. Pydantic refuses a bare number in a string, which
is the one spelling every environment variable uses, so this package
coerces it.
Connection
| Setting | Default | |
|---|---|---|
acemq.url |
amqp://localhost:5672/ |
amqps:// is encrypted, amqp:// is not |
acemq.username |
— | The login, kept out of the URL so a password stays out of a connection string that ends up in a log |
acemq.password |
— | A SecretStr; it does not appear in a
repr |
acemq.virtual_host |
— | Replaces whatever path the URL carried |
acemq.client_name |
acemq@{hostname} |
What is stamped on published messages |
acemq.format |
json |
One of acemq_amqp.codec_names() |
acemq.prefetch |
100 |
Unacknowledged messages a consumer holds |
acemq.publisher_confirms |
true |
Cannot be turned off. See below |
acemq.max_outstanding_publishes |
1000 |
Publishes that may be waiting at once |
acemq.confirm_timeout |
30s |
How long a publish waits for room, or for its confirm, before raising |
acemq.connection_timeout |
10s |
How long the lifespan gives the broker to answer |
publisher_confirms=false is refused,
with a message saying why, rather than accepted and ignored. The Python
library publishes with confirms always; a setting that silently did
nothing would leave a service believing it had traded safety for
throughput and having neither.
TLS — acemq.tls.*
Only consulted for an amqps:// URL. The library refuses
TLS settings against a plaintext URL rather than ignoring them, and this
passes that refusal through.
| Setting | Default | |
|---|---|---|
certificate_authority |
— | A PEM file. Naming one replaces the machine's trust store rather than adding to it |
client_certificate |
— | A PEM certificate to present |
client_key |
the certificate file | The PEM private key |
client_key_password |
— | The passphrase, when the key has one |
server_name |
the host in the URL | The name to check the certificate against |
verification |
certificate |
Or nothing-at-all, spelled that way so a config file
cannot hide what it is giving up behind a
verify: false |
allow_development_certificates |
false |
A laptop's settings copied into a deployment should fail loudly |
Consumers —
acemq.consumer.*
The defaults every registered consumer starts with; a registration overrides any of them per queue.
| Setting | Default | |
|---|---|---|
prefetch |
100 |
Also the bound on how many deliveries a shutdown hands back — see shutdown |
concurrency |
1 |
One keeps a queue's messages in order |
declare |
true |
Declare {queue}.dlq, {queue}.parked and
the rungs before subscribing |
auto_start |
true |
Off registers everything and starts nothing |
shutdown_timeout |
20s |
How long a drain gets before the handlers are cancelled |
acemq.consumer.retry.*
Off until asked for, matching the Spring starter: a ladder declares rung queues on the broker.
| Setting | Default | |
|---|---|---|
enabled |
false |
|
kind |
exponential |
Doubling with 20% jitter, or fixed |
max_attempts |
3 |
Total deliveries, the first included |
initial_delay |
1s |
The wait before the second attempt |
max_delay |
1m |
The ceiling |
give_up_after |
— | Give up on a message older than this, whatever attempt it is on |
wait_in_broker_from |
— | Waits at or above this live on a rung queue rather than in this process. Set it — see shutdown |
Topology —
acemq.topology.*
Declaring nothing is the default and is a real answer: a service that only consumes queues somebody else owns should not create them.
AceMQSettings(
topology={
"exchanges": [{"name": "events", "kind": "topic"}],
"queues": [{"name": "orders", "dead_letter": True}],
"bindings": [
{"queue": "orders", "exchange": "events", "routing_key": "order.*"}
],
}
)A queue is durable and, being durable, a
quorum queue unless it is asked to be something else.
That is not a preference: the queue type is an argument the broker
compares, so a Java service and a Python service that disagree about
orders cannot both consume it. quorum: false
declares a classic queue.
dead_letter: true brings {name}.dlq and
{name}.parked with it and points the broker at them.
declare_retry_rungs is on, so the rung queues the
consumer retry policy needs are declared with each queue. A policy whose
rungs are missing falls back to waiting in this process, which is the
slow drain nobody expects.
Health — acemq.health.*
| Setting | Default | |
|---|---|---|
path |
/health/acemq |
The route acemq.health_router() builds |
timeout |
5s |
How long the broker gets to answer. Handed to the library's probe as its deadline, rather than imposed around it |
unhealthy_status_code |
503 |
Answered only for down. Degraded and blocked answer 200 |
See health for why blocked answers 200, and why the timeout goes down into the probe instead of wrapping it.