11import json
22import pika
33import praw
4- from collections import deque
54from json import JSONEncoder
65from praw .models .mod_action import ModAction
76from praw .models .reddit .comment import Comment
87from praw .models .reddit .submission import Submission
98from types import FunctionType
10- from typing import Deque
119from uuid import UUID
1210
11+ from services import rabbitmq_pending_message_service
1312from data .comment_data import CommentModel
1413from data .mod_action_data import ModActionModel
1514from data .post_data import PostModel
@@ -34,8 +33,6 @@ def default(self, obj):
3433
3534
3635class RabbitService :
37- messages_to_retry : Deque [dict ] = deque ()
38-
3936 def __init__ (self , config_dict : dict ):
4037 self .config = config_dict
4138 self .connection = None
@@ -79,11 +76,7 @@ def __init__(self, config_dict: dict):
7976
8077 self .queues [key ] = {"exchange" : exchange_name , "queue" : queue_name }
8178
82- if self .messages_to_retry :
83- logger .info (f"Retrying { len (self .messages_to_retry )} RabbitMQ messages" )
84- while self .messages_to_retry :
85- exchange_name , queue_name , json_body = self .messages_to_retry .popleft ()
86- self ._publish_message (exchange_name , queue_name , json_body )
79+ self ._republish_messages ()
8780
8881 def init_connection (self , reconnect : bool = True ):
8982 logger .info (f"{ "Rec" if reconnect else "C" } onnecting to RabbitMQ..." )
@@ -95,21 +88,21 @@ def publish_post(self, reddit_post: Submission, post: PostModel, status: str = "
9588 logger .info (f"Publishing post to RabbitMQ: { reddit_post .id } ({ status } )" )
9689 queue = self .queues ["post" ]
9790 body = {"status" : status , "reddit" : reddit_post , "db" : post .to_dict ()}
98- self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ))
91+ self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ), "post" )
9992
10093 def publish_comment (self , reddit_comment : Comment , comment : CommentModel , status : str = "new" ):
10194 logger .info (f"Publishing comment to RabbitMQ: { reddit_comment .id } ({ status } )" )
10295 queue = self .queues ["comment" ]
10396 body = {"status" : status , "reddit" : reddit_comment , "db" : comment .to_dict ()}
104- self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ))
97+ self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ), "comment" )
10598
10699 def publish_mod_action (self , reddit_mod_action : ModAction , mod_action : ModActionModel , status : str = "new" ):
107100 logger .info (f"Publishing mod action to RabbitMQ: { reddit_mod_action .id } ({ status } )" )
108101 queue = self .queues ["mod_action" ]
109102 body = {"status" : status , "reddit" : reddit_mod_action , "db" : mod_action .to_dict ()}
110- self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ))
103+ self ._publish_message (queue ["exchange" ], queue ["queue" ], json .dumps (body , cls = PRAWJSONEncoder ), "mod action" )
111104
112- def _publish_message (self , exchange_name : str , queue_name : str , json_body : str ):
105+ def _publish_message (self , exchange_name : str , queue_name : str , json_body : str , type : str ):
113106 try :
114107 self .channel .basic_publish (
115108 exchange = exchange_name ,
@@ -136,6 +129,45 @@ def _publish_message(self, exchange_name: str, queue_name: str, json_body: str):
136129 )
137130 logger .info ("Successfully send message after reconnect" )
138131 except Exception :
139- logger .error ("Still couldn't connect to RabbitMQ. Saving message to retry memory list" )
140- self .messages_to_retry .append ((exchange_name , queue_name , json_body ))
132+ logger .exception ("Still couldn't connect to RabbitMQ. Saving message to retry table" )
133+ rabbitmq_pending_message_service .insert_pending_message (exchange_name , queue_name , json_body , type )
134+ raise
135+
136+ def _republish_messages (self ):
137+ messages_to_retry = rabbitmq_pending_message_service .get_pending_messages ()
138+ if messages_to_retry :
139+ logger .info (f"Retrying { len (messages_to_retry )} RabbitMQ messages" )
140+ number_of_successful_retries = 0
141+ for pending_message in messages_to_retry :
142+ logger .info (
143+ f"Republishing { pending_message .type } to RabbitMQ"
144+ + f": { pending_message .json_body ["reddit" ]["id" ]} ({ pending_message .json_body ["status" ]} )"
145+ )
146+ try :
147+ json_body = json .dumps (pending_message .json_body , cls = PRAWJSONEncoder )
148+ self ._republish_message (pending_message .exchange_name , pending_message .queue_name , json_body )
149+ number_of_successful_retries += rabbitmq_pending_message_service .delete_pending_message (pending_message )
150+ except Exception :
151+ if number_of_successful_retries > 0 :
152+ logger .warn (
153+ f"Successfully retried { number_of_successful_retries } "
154+ + f" / { len (messages_to_retry )} RabbitMQ messages"
155+ )
156+ logger .exception ("RabbitMQ is still down. Messages will stay pending." )
141157 raise
158+ logger .info (f"Successfully retried all { number_of_successful_retries } RabbitMQ messages" )
159+
160+ def _republish_message (self , exchange_name : str , queue_name : str , json_body : str ):
161+ try :
162+ self .channel .basic_publish (
163+ exchange = exchange_name ,
164+ routing_key = queue_name ,
165+ body = json_body ,
166+ properties = pika .BasicProperties (
167+ delivery_mode = pika .DeliveryMode .Persistent ,
168+ content_type = "application/json" ,
169+ headers = {self .config ["retry_attempt_header" ]: 1 },
170+ ),
171+ )
172+ except Exception :
173+ logger .exception ("Still couldn't connect to RabbitMQ. Message already saved to retry" )
0 commit comments