Service Bus has no message priority, so priority is separate queues with separate worker deployments and separate KEDA bounds. A single queue with a priority property would still be drained in arrival order and would deliver nothing.
Sessions are used only on the completions queue and the long-running task queue. Sessions serialise processing per session id, which is exactly right for ordering completions within one execution and exactly wrong for the general task queue.
Two dead-letter sources, one destination. Native dead-letters are infrastructure problems and application dead-letters are business problems, but an operator should never have to know which console to open, so dlq-drain merges both into one Cosmos-backed store.
Settings that matter
Lock duration 5 minutes with client-side auto-renewal to 2 hours for the long-running class. maxDeliveryCount is 10 as an infrastructure backstop; application retries never reach it because they are re-enqueued as new scheduled messages (view 19).
Prefetch is tuned per class — 8 for high priority, 32 standard, 64 bulk — because prefetch is the hidden concurrency limit that makes a fair-looking system unfair under load.
MessageId is set to the taskExecutionId with a 10-minute duplicate detection window, which suppresses relay-level double dispatch without pretending to give exactly-once.
Risks
A dedicated namespace per tier-1 tenant does not scale past a handful of tenants; namespace count and cost grow linearly. It is an escape hatch sold as a premium tier, not the isolation model (view 29).
Scheduled messages accumulate against the namespace quota. A tenant with a 5-minute maximum backoff and a failing downstream can hold tens of thousands of scheduled messages, which needs a monitor.
Event Grid dead-letters land in Blob and are not currently merged into the operator view. That is a known gap for V1.1.