11# Copyright © 2021 Ingram Micro Inc. All rights reserved.
22
3+ from dateutil .parser import parse as dateutil_parse
4+ from django .utils import timezone
5+
36from dj_cqrs .correlation import get_correlation_id
7+ from dj_cqrs .utils import get_expires_datetime
48
59
610class TransportPayload :
@@ -21,17 +25,23 @@ class TransportPayload:
2125 :type previous_data: dict, optional
2226 :param correlation_id: Correlation ID of process, where this payload is used.
2327 :type correlation_id: str, optional
28+ :param retries: Current number of message retries.
29+ :type retries: int, optional
30+ :param expires: Message expiration datetime, infinite if None
31+ :type expires: datetime, optional
2432 """
2533
2634 def __init__ (
27- self ,
28- signal_type ,
29- cqrs_id ,
30- instance_data ,
31- instance_pk ,
32- queue = None ,
33- previous_data = None ,
34- correlation_id = None ,
35+ self ,
36+ signal_type ,
37+ cqrs_id ,
38+ instance_data ,
39+ instance_pk ,
40+ queue = None ,
41+ previous_data = None ,
42+ correlation_id = None ,
43+ expires = None ,
44+ retries = 0 ,
3545 ):
3646 self .__signal_type = signal_type
3747 self .__cqrs_id = cqrs_id
@@ -45,6 +55,37 @@ def __init__(
4555 else :
4656 self .__correlation_id = get_correlation_id (signal_type , cqrs_id , instance_pk , queue )
4757
58+ self .__expires = expires
59+ self .__retries = retries
60+
61+ @classmethod
62+ def from_message (cls , dct ):
63+ """Builds payload from message data.
64+
65+ :param dct: Deserialized message body data.
66+ :type dct: dict
67+ :return: TransportPayload instance.
68+ :rtype: TransportPayload
69+ """
70+ if 'expires' in dct :
71+ expires = dct ['expires' ]
72+ if dct ['expires' ] is not None :
73+ expires = dateutil_parse (dct ['expires' ])
74+ else :
75+ # Backward compatibility for old messages otherwise they are infinite by default.
76+ expires = get_expires_datetime ()
77+
78+ return cls (
79+ dct ['signal_type' ],
80+ dct ['cqrs_id' ],
81+ dct ['instance_data' ],
82+ dct .get ('instance_pk' ),
83+ previous_data = dct .get ('previous_data' ),
84+ correlation_id = dct .get ('correlation_id' ),
85+ expires = expires ,
86+ retries = dct .get ('retries' ) or 0 ,
87+ )
88+
4889 @property
4990 def signal_type (self ):
5091 return self .__signal_type
@@ -73,18 +114,47 @@ def previous_data(self):
73114 def correlation_id (self ):
74115 return self .__correlation_id
75116
117+ @property
118+ def expires (self ):
119+ return self .__expires
120+
121+ @property
122+ def retries (self ):
123+ return self .__retries
124+
125+ @retries .setter
126+ def retries (self , value ):
127+ assert value >= 0 , "Payload retries field should be 0 or positive integer."
128+ self .__retries = value
129+
76130 def to_dict (self ):
77- """
78- Return the payload as a dictionary.
131+ """Return the payload as a dictionary.
79132
80133 :return: This payload.
81134 :rtype: dict
82135 """
136+ expires = self .__expires
137+ if expires :
138+ expires = expires .replace (microsecond = 0 ).isoformat ()
139+
83140 return {
84141 'signal_type' : self .__signal_type ,
85142 'cqrs_id' : self .__cqrs_id ,
86143 'instance_data' : self .__instance_data ,
87144 'previous_data' : self .__previous_data ,
88145 'instance_pk' : self .__instance_pk ,
89146 'correlation_id' : self .__correlation_id ,
147+ 'retries' : self .__retries ,
148+ 'expires' : expires ,
90149 }
150+
151+ def is_expired (self ):
152+ """Checks if this payload is expired.
153+
154+ :return: True if payload is expired, False otherwise.
155+ :rtype: bool
156+ """
157+ return (
158+ self .__expires is not None
159+ and self .__expires <= timezone .now ()
160+ )
0 commit comments