6
6
from socket import gaierror
7
7
from urllib .parse import unquote , urlparse
8
8
9
-
10
9
import ujson
11
10
from django .conf import settings
12
11
from pika import exceptions , BasicProperties , BlockingConnection , ConnectionParameters , credentials
24
23
class RabbitMQTransport (LoggingMixin , BaseTransport ):
25
24
CONSUMER_RETRY_TIMEOUT = 5
26
25
26
+ _producer_connection = None
27
+ _producer_channel = None
28
+
29
+ @classmethod
30
+ def clean_connection (cls ):
31
+ if cls ._producer_connection and not cls ._producer_connection .is_closed :
32
+ cls ._producer_connection .close ()
33
+ cls ._producer_connection = None
34
+ cls ._producer_channel = None
35
+
27
36
@classmethod
28
37
def consume (cls ):
29
38
consumer_rabbit_settings = cls ._get_consumer_settings ()
@@ -43,28 +52,29 @@ def consume(cls):
43
52
logger .error ('AMQP connection error. Reconnecting...' )
44
53
time .sleep (cls .CONSUMER_RETRY_TIMEOUT )
45
54
finally :
46
- if connection :
55
+ if connection and not connection . is_closed :
47
56
connection .close ()
48
57
49
58
@classmethod
50
59
def produce (cls , payload ):
60
+ # TODO: try to produce and reconnect several times, now leave as before
61
+ # if cannot publish message - drop it and try to reconnect on next event
51
62
rmq_settings = cls ._get_common_settings ()
52
63
exchange = rmq_settings [- 1 ]
53
64
54
- connection = None
55
65
try :
56
66
# Decided not to create context-manager to stay within the class
57
- connection , channel = cls ._get_producer_rmq_objects (* rmq_settings )
67
+ _ , channel = cls ._get_producer_rmq_objects (* rmq_settings )
58
68
59
69
cls ._produce_message (channel , exchange , payload )
60
70
cls .log_produced (payload )
61
71
except (exceptions .AMQPError , exceptions .ChannelError , exceptions .ReentrancyError ):
62
72
logger .error ("CQRS couldn't be published: pk = {} ({})." .format (
63
73
payload .pk , payload .cqrs_id ,
64
74
))
65
- finally :
66
- if connection :
67
- connection . close ()
75
+
76
+ # in case of any error - close connection and try to reconnect
77
+ cls . clean_connection ()
68
78
69
79
@classmethod
70
80
def _consume_message (cls , ch , method , properties , body ):
@@ -114,7 +124,7 @@ def _produce_message(cls, channel, exchange, payload):
114
124
properties = BasicProperties (
115
125
content_type = 'text/plain' ,
116
126
delivery_mode = 2 , # make message persistent
117
- expiration = ' 60000' , # milliseconds
127
+ expiration = settings . CQRS . get ( 'MESSAGE_TTL' , ' 60000') , # milliseconds
118
128
)
119
129
)
120
130
@@ -159,18 +169,22 @@ def _get_consumer_rmq_objects(cls, host, port, creds, exchange, queue_name, pref
159
169
160
170
@classmethod
161
171
def _get_producer_rmq_objects (cls , host , port , creds , exchange ):
162
- connection = BlockingConnection (
163
- ConnectionParameters (
164
- host = host ,
165
- port = port ,
166
- credentials = creds ,
167
- blocked_connection_timeout = 10 ,
168
- ),
169
- )
170
- channel = connection .channel ()
171
- cls ._declare_exchange (channel , exchange )
172
+ if cls ._producer_connection is None :
173
+ connection = BlockingConnection (
174
+ ConnectionParameters (
175
+ host = host ,
176
+ port = port ,
177
+ credentials = creds ,
178
+ blocked_connection_timeout = 10 ,
179
+ ),
180
+ )
181
+ channel = connection .channel ()
182
+ cls ._declare_exchange (channel , exchange )
172
183
173
- return connection , channel
184
+ cls ._producer_connection = connection
185
+ cls ._producer_channel = channel
186
+
187
+ return cls ._producer_connection , cls ._producer_channel
174
188
175
189
@staticmethod
176
190
def _declare_exchange (channel , exchange ):
0 commit comments