acemq_amqp.headers
The names AceMQ puts on the wire.
These are the contract between languages, not an implementation detail of this
one. A Python consumer reads what a Java producer wrote because both agree on
the strings in this module and on the types of their values, so nothing here is
renamed for Python's benefit — x-acemq-first-seen stays hyphenated and
stays epoch milliseconds, however un-Pythonic that looks.
The set is pinned by tests/fixtures/envelope-fixtures.json, which is
generated by the Java implementation and shared with the Go and .NET ones.
1# Copyright 2026 AceMQ. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""The names AceMQ puts on the wire. 16 17These are the contract between languages, not an implementation detail of this 18one. A Python consumer reads what a Java producer wrote because both agree on 19the strings in this module and on the types of their values, so nothing here is 20renamed for Python's benefit — ``x-acemq-first-seen`` stays hyphenated and 21stays epoch milliseconds, however un-Pythonic that looks. 22 23The set is pinned by ``tests/fixtures/envelope-fixtures.json``, which is 24generated by the Java implementation and shared with the Go and .NET ones. 25""" 26 27from __future__ import annotations 28 29#: The unique message identifier, and the default idempotency key. 30ID = "x-acemq-id" 31 32#: The logical message type, for example ``order.placed.v2``. 33TYPE = "x-acemq-type" 34 35#: The schema version of the payload, as an integer starting at 1. 36VERSION = "x-acemq-version" 37 38#: The business correlation identifier, propagated across hops. 39CORRELATION = "x-acemq-correlation" 40 41#: The message that caused this one, absent when there was none. 42CAUSATION = "x-acemq-causation" 43 44#: The delivery attempt, as an integer starting at 1. 45ATTEMPT = "x-acemq-attempt" 46 47#: When the message was first published, as epoch milliseconds. 48FIRST_SEEN = "x-acemq-first-seen" 49 50#: The publishing process, conventionally ``service@host``. 51ORIGIN = "x-acemq-origin" 52 53#: Why a message was dead-lettered, present only when it was. 54ERROR = "x-acemq-error" 55 56#: The claim-check URI, when the payload is stored outside the message. 57CLAIM = "x-acemq-claim" 58 59#: The steps of a declared route, by name, comma-separated and in order. 60#: 61#: The form Java's ``Pipeline`` writes: a route declared once and resolved 62#: against that declaration at each hop, so the wire carries 63#: ``validate,enrich,dispatch`` and nothing about where those steps live. The 64#: self-describing form, which carries an exchange and a routing key per step, 65#: is the ``acemq-routing-slip`` application header that 66#: :mod:`acemq_amqp.patterns.routingslip` writes by default. Python reads both 67#: and can write either. 68ROUTE = "x-acemq-route" 69 70#: Which step of :data:`ROUTE` this message is for, counting from zero. 71ROUTE_POSITION = "x-acemq-route-position" 72 73#: One run through a route, carried by every hop, and surviving a dead-letter 74#: and a replay so that the whole run can be found from any message in it. 75ROUTE_ID = "x-acemq-route-id" 76 77#: The prefix every reserved name shares. 78PREFIX = "x-acemq-" 79 80#: W3C trace context. **Deliberately not prefixed**, unlike everything above. 81#: 82#: These two are not AceMQ's names to choose. They are the ones the W3C 83#: specification defines and every piece of tracing tooling already reads, so a 84#: message published here joins up in a consumer written with no knowledge of 85#: this library, and a message published by such a consumer joins up here. 86#: Prefixing them would have been consistent with the rest of this module and 87#: would have made the trace context private to AceMQ, which is the exact 88#: opposite of what a propagation format is for. Java, Go and .NET write these 89#: same two names for the same reason. 90#: 91#: They are application headers, not reserved ones: they belong to whatever 92#: wrote them, they are copied rather than re-derived, and 93#: :mod:`acemq_amqp.tracing` is what puts them on a message. 94TRACEPARENT = "traceparent" 95 96#: The vendor-specific half of the W3C trace context. See :data:`TRACEPARENT`. 97TRACESTATE = "tracestate" 98 99#: Every name this library writes and understands. 100RESERVED = frozenset( 101 { 102 ID, 103 TYPE, 104 VERSION, 105 CORRELATION, 106 CAUSATION, 107 ATTEMPT, 108 FIRST_SEEN, 109 ORIGIN, 110 ERROR, 111 CLAIM, 112 ROUTE, 113 ROUTE_POSITION, 114 ROUTE_ID, 115 } 116) 117 118 119def is_reserved(name: str) -> bool: 120 """Whether a header name belongs to AceMQ rather than to the application. 121 122 Matches on the prefix rather than on the known set: a header from a newer 123 version of another language's library is still not the application's, and 124 handing it back as though it were would have an application unknowingly 125 copy it onto a message it publishes. 126 127 :param name: a header name 128 :returns: whether AceMQ reserves it 129 """ 130 return name.startswith(PREFIX)
120def is_reserved(name: str) -> bool: 121 """Whether a header name belongs to AceMQ rather than to the application. 122 123 Matches on the prefix rather than on the known set: a header from a newer 124 version of another language's library is still not the application's, and 125 handing it back as though it were would have an application unknowingly 126 copy it onto a message it publishes. 127 128 :param name: a header name 129 :returns: whether AceMQ reserves it 130 """ 131 return name.startswith(PREFIX)
Whether a header name belongs to AceMQ rather than to the application.
Matches on the prefix rather than on the known set: a header from a newer version of another language's library is still not the application's, and handing it back as though it were would have an application unknowingly copy it onto a message it publishes.
Parameters
- name: a header name :returns: whether AceMQ reserves it