0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling Service Bus errors including connection issues, authentication failures, message processing errors, and service-side exceptions.
3
4
## Capabilities
5
6
### Base Exception
7
8
Root exception class for all Service Bus-specific errors.
9
10
```python { .api }
11
class ServiceBusError(AzureError):
12
"""
13
Base exception for all Service Bus errors.
14
15
Provides common error handling for all Service Bus operations and includes
16
retry information and error context.
17
"""
18
def __init__(
19
self,
20
message: Optional[Union[str, bytes]],
21
*args,
22
**kwargs
23
) -> None:
24
"""
25
Initialize ServiceBusError.
26
27
Parameters:
28
- message: Error message (string or bytes)
29
- retryable: Whether the operation can be retried (keyword arg)
30
- shutdown_handler: Whether to shutdown handler on error (keyword arg)
31
- condition: AMQP error condition (keyword arg)
32
- status_code: HTTP status code if applicable (keyword arg)
33
"""
34
35
@property
36
def retryable(self) -> bool:
37
"""Whether this error indicates a retryable condition."""
38
39
@property
40
def shutdown_handler(self) -> bool:
41
"""Whether the handler should be shutdown due to this error."""
42
43
@property
44
def condition(self) -> Optional[str]:
45
"""AMQP error condition if available."""
46
47
@property
48
def status_code(self) -> Optional[int]:
49
"""HTTP status code if applicable."""
50
```
51
52
#### Usage Example
53
54
```python
55
from azure.servicebus import ServiceBusClient
56
from azure.servicebus.exceptions import ServiceBusError
57
58
client = ServiceBusClient.from_connection_string("your_connection_string")
59
60
try:
61
with client.get_queue_sender("my-queue") as sender:
62
sender.send_messages(ServiceBusMessage("Hello"))
63
64
except ServiceBusError as e:
65
print(f"Service Bus error: {e}")
66
print(f"Retryable: {e.retryable}")
67
print(f"Status code: {e.status_code}")
68
print(f"Condition: {e.condition}")
69
70
if e.retryable:
71
# Implement retry logic
72
retry_operation()
73
else:
74
# Handle non-retryable error
75
handle_permanent_failure()
76
```
77
78
### Connection and Communication Errors
79
80
Exceptions related to network connectivity and communication with Service Bus.
81
82
```python { .api }
83
class ServiceBusConnectionError(ServiceBusError):
84
"""
85
An error occurred in the connection to Service Bus.
86
87
This is a retryable error that typically indicates network issues
88
or temporary service unavailability.
89
"""
90
91
class ServiceBusCommunicationError(ServiceBusError):
92
"""
93
A general communications error when interacting with Service Bus.
94
95
Client cannot establish or maintain a connection to Service Bus.
96
Check network connectivity, firewall settings, and Service Bus availability.
97
"""
98
```
99
100
#### Usage Example
101
102
```python
103
from azure.servicebus import ServiceBusClient
104
from azure.servicebus.exceptions import (
105
ServiceBusConnectionError,
106
ServiceBusCommunicationError
107
)
108
import time
109
110
client = ServiceBusClient.from_connection_string("your_connection_string")
111
112
def send_with_retry(message, max_retries=3):
113
for attempt in range(max_retries):
114
try:
115
with client.get_queue_sender("my-queue") as sender:
116
sender.send_messages(message)
117
return # Success
118
119
except ServiceBusConnectionError as e:
120
print(f"Connection error (attempt {attempt + 1}): {e}")
121
if attempt < max_retries - 1:
122
time.sleep(2 ** attempt) # Exponential backoff
123
else:
124
raise
125
126
except ServiceBusCommunicationError as e:
127
print(f"Communication error: {e}")
128
print("Check network connectivity and firewall settings")
129
raise
130
```
131
132
### Authentication and Authorization Errors
133
134
Exceptions related to credential validation and access permissions.
135
136
```python { .api }
137
class ServiceBusAuthenticationError(ServiceBusError):
138
"""
139
An error occurred when authenticating the connection.
140
141
Credential validation failed. Check that credentials are valid
142
and not expired.
143
"""
144
145
class ServiceBusAuthorizationError(ServiceBusError):
146
"""
147
An error occurred when authorizing the connection.
148
149
Access to the requested resource is denied. Check that the credential
150
has appropriate permissions for the operation.
151
"""
152
```
153
154
#### Usage Example
155
156
```python
157
from azure.servicebus import ServiceBusClient
158
from azure.servicebus.exceptions import (
159
ServiceBusAuthenticationError,
160
ServiceBusAuthorizationError
161
)
162
163
try:
164
client = ServiceBusClient.from_connection_string("invalid_connection_string")
165
with client.get_queue_sender("my-queue") as sender:
166
sender.send_messages(ServiceBusMessage("Hello"))
167
168
except ServiceBusAuthenticationError as e:
169
print(f"Authentication failed: {e}")
170
print("Check connection string and credentials")
171
172
except ServiceBusAuthorizationError as e:
173
print(f"Authorization failed: {e}")
174
print("Check that the credential has Send permissions for the queue")
175
```
176
177
### Message Processing Errors
178
179
Exceptions related to message handling and settlement operations.
180
181
```python { .api }
182
class MessageAlreadySettled(ValueError):
183
"""
184
Failed to settle the message because it was already settled.
185
186
An attempt was made to complete, abandon, defer, or dead-letter a message
187
that has already been settled. This is not a retryable error.
188
"""
189
190
class MessageLockLostError(ServiceBusError):
191
"""
192
The lock on the message has expired.
193
194
The message lock has expired and the message is no longer exclusively
195
locked to this receiver. The message will become available to other
196
receivers. This is not a retryable error for the same message instance.
197
"""
198
199
class MessageNotFoundError(ServiceBusError):
200
"""
201
The requested message was not found.
202
203
Attempt to receive a message with a specific sequence number failed
204
because the message no longer exists or has been processed.
205
"""
206
207
class MessageSizeExceededError(ServiceBusError, ValueError):
208
"""
209
Message content is larger than the Service Bus frame size limit.
210
211
The message exceeds the maximum allowed size. Reduce message size
212
or split into multiple messages.
213
"""
214
```
215
216
#### Usage Example
217
218
```python
219
from azure.servicebus import ServiceBusClient, ServiceBusMessage
220
from azure.servicebus.exceptions import (
221
MessageAlreadySettled,
222
MessageLockLostError,
223
MessageNotFoundError,
224
MessageSizeExceededError
225
)
226
import time
227
228
client = ServiceBusClient.from_connection_string("your_connection_string")
229
230
def process_messages_safely():
231
with client.get_queue_receiver("my-queue") as receiver:
232
messages = receiver.receive_messages(max_message_count=10)
233
234
for message in messages:
235
try:
236
# Simulate long processing
237
result = process_message(message)
238
239
# Attempt to complete the message
240
receiver.complete_message(message)
241
print(f"Successfully processed: {result}")
242
243
except MessageAlreadySettled:
244
print("Message was already settled by another process")
245
continue
246
247
except MessageLockLostError:
248
print(f"Message lock expired during processing: {message.sequence_number}")
249
# Message will be available for other receivers
250
continue
251
252
except Exception as processing_error:
253
print(f"Error processing message: {processing_error}")
254
try:
255
receiver.abandon_message(message)
256
except MessageAlreadySettled:
257
print("Message was already settled during error handling")
258
259
def send_large_message():
260
try:
261
# Create a very large message
262
large_content = "x" * (1024 * 1024 * 2) # 2MB message
263
message = ServiceBusMessage(large_content)
264
265
with client.get_queue_sender("my-queue") as sender:
266
sender.send_messages(message)
267
268
except MessageSizeExceededError as e:
269
print(f"Message too large: {e}")
270
print("Consider using message batching or splitting the message")
271
```
272
273
### Session-Related Errors
274
275
Exceptions specific to session-enabled messaging scenarios.
276
277
```python { .api }
278
class SessionLockLostError(ServiceBusError):
279
"""
280
The lock on the session has expired.
281
282
All unsettled messages that have been received can no longer be settled.
283
The session must be re-acquired to continue processing.
284
"""
285
286
class SessionCannotBeLockedError(ServiceBusError):
287
"""
288
The requested session cannot be locked.
289
290
The session is currently locked by another client, does not exist,
291
or the session ID is invalid.
292
"""
293
```
294
295
#### Usage Example
296
297
```python
298
from azure.servicebus import ServiceBusClient, NEXT_AVAILABLE_SESSION
299
from azure.servicebus.exceptions import (
300
SessionLockLostError,
301
SessionCannotBeLockedError
302
)
303
304
client = ServiceBusClient.from_connection_string("your_connection_string")
305
306
def process_session_safely(session_id):
307
try:
308
with client.get_queue_receiver("my-session-queue", session_id=session_id) as receiver:
309
session = receiver.session
310
311
messages = receiver.receive_messages(max_message_count=10)
312
for message in messages:
313
try:
314
# Process message with session state
315
process_with_session_state(message, session)
316
receiver.complete_message(message)
317
318
except SessionLockLostError:
319
print(f"Session {session_id} lock expired")
320
break # Exit and let session be re-acquired
321
322
except SessionCannotBeLockedError:
323
print(f"Cannot lock session {session_id} - trying next available")
324
325
# Try to get any available session instead
326
try:
327
with client.get_queue_receiver("my-session-queue", session_id=NEXT_AVAILABLE_SESSION) as receiver:
328
if receiver.session:
329
print(f"Got available session: {receiver.session.session_id}")
330
# Process this session instead
331
else:
332
print("No sessions available")
333
except SessionCannotBeLockedError:
334
print("No sessions available at all")
335
```
336
337
### Entity Management Errors
338
339
Exceptions related to Service Bus entity operations.
340
341
```python { .api }
342
class MessagingEntityNotFoundError(ServiceBusError):
343
"""
344
A Service Bus resource cannot be found.
345
346
The entity (queue, topic, subscription, or rule) associated with the
347
operation does not exist or has been deleted.
348
"""
349
350
class MessagingEntityDisabledError(ServiceBusError):
351
"""
352
The messaging entity is disabled.
353
354
The entity exists but is disabled and cannot process messages.
355
Enable the entity using the Azure portal or management API.
356
"""
357
358
class MessagingEntityAlreadyExistsError(ServiceBusError):
359
"""
360
An entity with the same name already exists.
361
362
Cannot create an entity because one with the same name already exists
363
in the namespace.
364
"""
365
```
366
367
#### Usage Example
368
369
```python
370
from azure.servicebus import ServiceBusClient, ServiceBusMessage
371
from azure.servicebus.exceptions import (
372
MessagingEntityNotFoundError,
373
MessagingEntityDisabledError
374
)
375
from azure.servicebus.management import ServiceBusAdministrationClient
376
from azure.servicebus.exceptions import MessagingEntityAlreadyExistsError
377
378
client = ServiceBusClient.from_connection_string("your_connection_string")
379
admin_client = ServiceBusAdministrationClient.from_connection_string("your_connection_string")
380
381
def safe_queue_operations(queue_name):
382
try:
383
# Try to send to queue
384
with client.get_queue_sender(queue_name) as sender:
385
sender.send_messages(ServiceBusMessage("Hello"))
386
387
except MessagingEntityNotFoundError:
388
print(f"Queue {queue_name} does not exist - creating it")
389
try:
390
admin_client.create_queue(queue_name)
391
print(f"Created queue {queue_name}")
392
# Retry the send operation
393
with client.get_queue_sender(queue_name) as sender:
394
sender.send_messages(ServiceBusMessage("Hello"))
395
except MessagingEntityAlreadyExistsError:
396
print(f"Queue {queue_name} was created by another process")
397
398
except MessagingEntityDisabledError:
399
print(f"Queue {queue_name} is disabled - check Azure portal")
400
```
401
402
### Service-Level Errors
403
404
Exceptions related to Service Bus service conditions and limits.
405
406
```python { .api }
407
class ServiceBusQuotaExceededError(ServiceBusError):
408
"""
409
A Service Bus resource quota has been exceeded.
410
411
The messaging entity has reached its maximum size, or the maximum
412
number of connections to a namespace has been exceeded.
413
"""
414
415
class ServiceBusServerBusyError(ServiceBusError):
416
"""
417
The Service Bus service reports that it is busy.
418
419
The service cannot process the request at this time. Client should
420
wait and retry the operation after a delay.
421
"""
422
423
class OperationTimeoutError(ServiceBusError):
424
"""
425
The operation timed out.
426
427
The operation did not complete within the specified timeout period.
428
This is typically a retryable error.
429
"""
430
```
431
432
#### Usage Example
433
434
```python
435
from azure.servicebus import ServiceBusClient
436
from azure.servicebus.exceptions import (
437
ServiceBusQuotaExceededError,
438
ServiceBusServerBusyError,
439
OperationTimeoutError
440
)
441
import time
442
import random
443
444
client = ServiceBusClient.from_connection_string("your_connection_string")
445
446
def send_with_service_error_handling(message):
447
max_retries = 5
448
base_delay = 1
449
450
for attempt in range(max_retries):
451
try:
452
with client.get_queue_sender("my-queue", timeout=30) as sender:
453
sender.send_messages(message)
454
return # Success
455
456
except ServiceBusQuotaExceededError as e:
457
print(f"Quota exceeded: {e}")
458
print("Cannot send more messages - queue/namespace is full")
459
raise # Don't retry quota errors
460
461
except ServiceBusServerBusyError as e:
462
print(f"Service busy (attempt {attempt + 1}): {e}")
463
if attempt < max_retries - 1:
464
# Exponential backoff with jitter
465
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
466
time.sleep(delay)
467
else:
468
raise
469
470
except OperationTimeoutError as e:
471
print(f"Operation timeout (attempt {attempt + 1}): {e}")
472
if attempt < max_retries - 1:
473
time.sleep(base_delay * (attempt + 1))
474
else:
475
raise
476
```
477
478
### Lock Renewal Errors
479
480
Exceptions related to automatic lock renewal operations.
481
482
```python { .api }
483
class AutoLockRenewFailed(ServiceBusError):
484
"""
485
An attempt to renew a lock on a message or session in the background has failed.
486
487
The auto-renewal process encountered an error. Check the specific error
488
details to determine if manual intervention is required.
489
"""
490
491
class AutoLockRenewTimeout(ServiceBusError):
492
"""
493
The time allocated to renew the message or session lock has elapsed.
494
495
The maximum renewal duration has been reached and no further renewal
496
attempts will be made.
497
"""
498
```
499
500
#### Usage Example
501
502
```python
503
from azure.servicebus import ServiceBusClient, AutoLockRenewer
504
from azure.servicebus.exceptions import (
505
AutoLockRenewFailed,
506
AutoLockRenewTimeout
507
)
508
509
def handle_auto_renew_errors(renewable, error):
510
"""Callback for auto-renewal failures."""
511
if isinstance(error, AutoLockRenewFailed):
512
print(f"Auto-renewal failed for {renewable}: {error}")
513
# Log the error and potentially implement fallback logic
514
515
elif isinstance(error, AutoLockRenewTimeout):
516
print(f"Auto-renewal timeout for {renewable}: {error}")
517
# The renewal period has ended - message/session lock will expire
518
519
else:
520
print(f"Unexpected auto-renewal error: {error}")
521
522
client = ServiceBusClient.from_connection_string("your_connection_string")
523
auto_renewer = AutoLockRenewer(
524
max_lock_renewal_duration=300, # 5 minutes
525
on_lock_renew_failure=handle_auto_renew_errors
526
)
527
528
try:
529
with client.get_queue_receiver("my-queue") as receiver:
530
messages = receiver.receive_messages(max_message_count=5)
531
532
for message in messages:
533
# Register for auto-renewal
534
auto_renewer.register(message, timeout=300)
535
536
try:
537
# Long-running processing
538
result = long_running_process(message)
539
receiver.complete_message(message)
540
541
except Exception as e:
542
print(f"Processing error: {e}")
543
receiver.abandon_message(message)
544
545
finally:
546
auto_renewer.close()
547
```
548
549
## Error Handling Best Practices
550
551
### Comprehensive Error Handling Pattern
552
553
```python
554
from azure.servicebus import ServiceBusClient, ServiceBusMessage, AutoLockRenewer
555
from azure.servicebus.exceptions import *
556
from azure.servicebus.management import ServiceBusAdministrationClient
557
import logging
558
import time
559
560
logging.basicConfig(level=logging.INFO)
561
logger = logging.getLogger(__name__)
562
563
def robust_message_processing():
564
client = ServiceBusClient.from_connection_string("your_connection_string")
565
566
try:
567
with client.get_queue_receiver("my-queue") as receiver:
568
while True:
569
try:
570
messages = receiver.receive_messages(
571
max_message_count=10,
572
max_wait_time=30
573
)
574
575
if not messages:
576
logger.info("No messages received")
577
continue
578
579
for message in messages:
580
try:
581
# Process individual message
582
process_single_message(receiver, message)
583
584
except MessageAlreadySettled:
585
logger.warning(f"Message {message.sequence_number} already settled")
586
continue
587
588
except MessageLockLostError:
589
logger.warning(f"Lock lost for message {message.sequence_number}")
590
continue
591
592
except OperationTimeoutError:
593
logger.info("Receive operation timed out - continuing")
594
continue
595
596
except ServiceBusServerBusyError:
597
logger.warning("Service busy - backing off")
598
time.sleep(30)
599
continue
600
601
except MessagingEntityNotFoundError:
602
logger.error("Queue not found - exiting")
603
break
604
605
except (ServiceBusConnectionError, ServiceBusCommunicationError) as e:
606
logger.error(f"Connection issue: {e} - retrying")
607
time.sleep(5)
608
continue
609
610
except ServiceBusAuthenticationError:
611
logger.error("Authentication failed - check credentials")
612
raise
613
614
except ServiceBusAuthorizationError:
615
logger.error("Authorization failed - check permissions")
616
raise
617
618
finally:
619
client.close()
620
621
def process_single_message(receiver, message):
622
"""Process a single message with proper error handling."""
623
try:
624
# Your message processing logic here
625
result = your_message_processor(message)
626
receiver.complete_message(message)
627
logger.info(f"Successfully processed message {message.sequence_number}")
628
629
except Exception as processing_error:
630
logger.error(f"Error processing message {message.sequence_number}: {processing_error}")
631
632
# Decide whether to abandon or dead-letter based on error type and delivery count
633
if message.delivery_count and message.delivery_count >= 3:
634
receiver.dead_letter_message(
635
message,
636
reason="ProcessingFailed",
637
error_description=str(processing_error)
638
)
639
logger.warning(f"Dead-lettered message {message.sequence_number} after {message.delivery_count} attempts")
640
else:
641
receiver.abandon_message(message)
642
logger.info(f"Abandoned message {message.sequence_number} for retry")
643
```
644
645
This comprehensive error handling pattern demonstrates how to handle all major exception types that can occur during Service Bus operations, with appropriate retry logic and logging.