6
6
7
7
import datetime
8
8
import uuid
9
+ import functools
10
+ import logging
9
11
from typing import Optional , List , Union , Generator
10
12
11
13
import uamqp
12
- from uamqp import types
14
+ from uamqp import types , errors
13
15
14
16
from .constants import (
15
17
_BATCH_MESSAGE_OVERHEAD_COST ,
34
36
MESSAGE_DEAD_LETTER ,
35
37
MESSAGE_ABANDON ,
36
38
MESSAGE_DEFER ,
37
- MESSAGE_RENEW_LOCK
39
+ MESSAGE_RENEW_LOCK ,
40
+ DEADLETTERNAME
38
41
)
39
42
from ..exceptions import (
40
43
MessageAlreadySettled ,
44
47
)
45
48
from .utils import utc_from_timestamp , utc_now
46
49
50
+ _LOGGER = logging .getLogger (__name__ )
51
+
47
52
48
53
class Message (object ): # pylint: disable=too-many-public-methods,too-many-instance-attributes
49
54
"""A Service Bus Message.
@@ -436,9 +441,10 @@ class ReceivedMessage(PeekMessage):
436
441
:dedent: 4
437
442
:caption: Checking the properties on a received message.
438
443
"""
439
- def __init__ (self , message , mode = ReceiveSettleMode .PeekLock ):
444
+ def __init__ (self , message , mode = ReceiveSettleMode .PeekLock , ** kwargs ):
440
445
super (ReceivedMessage , self ).__init__ (message = message )
441
446
self ._settled = (mode == ReceiveSettleMode .ReceiveAndDelete )
447
+ self ._is_deferred_message = kwargs .get ("is_deferred_message" , False )
442
448
self .auto_renew_error = None
443
449
444
450
def _is_live (self , action ):
@@ -458,6 +464,69 @@ def _is_live(self, action):
458
464
except AttributeError :
459
465
pass
460
466
467
+ def _settle_message (
468
+ self ,
469
+ settle_operation ,
470
+ dead_letter_details = None
471
+ ):
472
+ try :
473
+ if not self ._is_deferred_message :
474
+ try :
475
+ self ._settle_via_receiver_link (settle_operation , dead_letter_details )()
476
+ return
477
+ except RuntimeError as exception :
478
+ _LOGGER .info (
479
+ "Message settling: %r has encountered an exception (%r)."
480
+ "Trying to settle through management link" ,
481
+ settle_operation ,
482
+ exception
483
+ )
484
+ self ._settle_via_mgmt_link (settle_operation , dead_letter_details )()
485
+ except Exception as e :
486
+ raise MessageSettleFailed (settle_operation , e )
487
+
488
+ def _settle_via_mgmt_link (self , settle_operation , dead_letter_details = None ):
489
+ # pylint: disable=protected-access
490
+ if settle_operation == MESSAGE_COMPLETE :
491
+ return functools .partial (
492
+ self ._receiver ._settle_message ,
493
+ SETTLEMENT_COMPLETE ,
494
+ [self .lock_token ],
495
+ )
496
+ if settle_operation == MESSAGE_ABANDON :
497
+ return functools .partial (
498
+ self ._receiver ._settle_message ,
499
+ SETTLEMENT_ABANDON ,
500
+ [self .lock_token ],
501
+ )
502
+ if settle_operation == MESSAGE_DEAD_LETTER :
503
+ return functools .partial (
504
+ self ._receiver ._settle_message ,
505
+ SETTLEMENT_DEADLETTER ,
506
+ [self .lock_token ],
507
+ dead_letter_details = dead_letter_details
508
+ )
509
+ if settle_operation == MESSAGE_DEFER :
510
+ return functools .partial (
511
+ self ._receiver ._settle_message ,
512
+ SETTLEMENT_DEFER ,
513
+ [self .lock_token ],
514
+ )
515
+ raise ValueError ("Unsupported settle operation type: {}" .format (settle_operation ))
516
+
517
+ def _settle_via_receiver_link (self , settle_operation , dead_letter_details = None ):
518
+ if settle_operation == MESSAGE_COMPLETE :
519
+ return functools .partial (self .message .accept )
520
+ if settle_operation == MESSAGE_ABANDON :
521
+ return functools .partial (self .message .modify , True , False )
522
+ if settle_operation == MESSAGE_DEAD_LETTER :
523
+ # note: message.reject() can not set reason and description properly due to the issue
524
+ # https://github.com/Azure/azure-uamqp-python/issues/155
525
+ return functools .partial (self .message .reject , condition = DEADLETTERNAME )
526
+ if settle_operation == MESSAGE_DEFER :
527
+ return functools .partial (self .message .modify , True , True )
528
+ raise ValueError ("Unsupported settle operation type: {}" .format (settle_operation ))
529
+
461
530
@property
462
531
def settled (self ):
463
532
# type: () -> bool
@@ -535,11 +604,9 @@ def complete(self):
535
604
:raises: ~azure.servicebus.common.errors.SessionLockExpired if session lock has already expired.
536
605
:raises: ~azure.servicebus.common.errors.MessageSettleFailed if message settle operation fails.
537
606
"""
607
+ # pylint: disable=protected-access
538
608
self ._is_live (MESSAGE_COMPLETE )
539
- try :
540
- self ._receiver ._settle_message (SETTLEMENT_COMPLETE , [self .lock_token ]) # pylint: disable=protected-access
541
- except Exception as e :
542
- raise MessageSettleFailed (MESSAGE_COMPLETE , e )
609
+ self ._settle_message (MESSAGE_COMPLETE )
543
610
self ._settled = True
544
611
545
612
def dead_letter (self , reason = None , description = None ):
@@ -560,17 +627,12 @@ def dead_letter(self, reason=None, description=None):
560
627
"""
561
628
# pylint: disable=protected-access
562
629
self ._is_live (MESSAGE_DEAD_LETTER )
630
+
563
631
details = {
564
632
MGMT_REQUEST_DEAD_LETTER_REASON : str (reason ) if reason else "" ,
565
633
MGMT_REQUEST_DEAD_LETTER_DESCRIPTION : str (description ) if description else "" }
566
- try :
567
- self ._receiver ._settle_message (
568
- SETTLEMENT_DEADLETTER ,
569
- [self .lock_token ],
570
- dead_letter_details = details
571
- )
572
- except Exception as e :
573
- raise MessageSettleFailed (MESSAGE_DEAD_LETTER , e )
634
+
635
+ self ._settle_message (MESSAGE_DEAD_LETTER , dead_letter_details = details )
574
636
self ._settled = True
575
637
576
638
def abandon (self ):
@@ -585,11 +647,9 @@ def abandon(self):
585
647
:raises: ~azure.servicebus.common.errors.SessionLockExpired if session lock has already expired.
586
648
:raises: ~azure.servicebus.common.errors.MessageSettleFailed if message settle operation fails.
587
649
"""
650
+ # pylint: disable=protected-access
588
651
self ._is_live (MESSAGE_ABANDON )
589
- try :
590
- self ._receiver ._settle_message (SETTLEMENT_ABANDON , [self .lock_token ]) # pylint: disable=protected-access
591
- except Exception as e :
592
- raise MessageSettleFailed (MESSAGE_ABANDON , e )
652
+ self ._settle_message (MESSAGE_ABANDON )
593
653
self ._settled = True
594
654
595
655
def defer (self ):
@@ -606,10 +666,7 @@ def defer(self):
606
666
:raises: ~azure.servicebus.common.errors.MessageSettleFailed if message settle operation fails.
607
667
"""
608
668
self ._is_live (MESSAGE_DEFER )
609
- try :
610
- self ._receiver ._settle_message (SETTLEMENT_DEFER , [self .lock_token ]) # pylint: disable=protected-access
611
- except Exception as e :
612
- raise MessageSettleFailed (MESSAGE_DEFER , e )
669
+ self ._settle_message (MESSAGE_DEFER )
613
670
self ._settled = True
614
671
615
672
def renew_lock (self ):
0 commit comments