1use async_rs::traits::{Executor, Reactor};
4use async_rs::Runtime;
5use futures::lock::Mutex;
6use futures::Future;
7use lapin::types::{AMQPValue, ShortUInt};
8use lapin::{Channel, Connection, ConnectionProperties, ConnectionState};
9use std::collections::HashMap;
10use std::pin::Pin;
11use std::sync::{Arc, Weak};
12use crate::config::Config;
14use crate::exchanges::DeclareExchange;
15
16pub const MAX_CHANNELS: usize = 16;
17use tokio::sync::mpsc::{channel, Receiver, Sender};
18
19pub type CreatorResult<T> = Pin<Box<dyn Future<Output = anyhow::Result<T>> + Send>>;
21pub type Creator<T> =
23 Pin<Box<dyn Fn(Arc<Channel>, Option<Arc<DeclareExchange>>) -> CreatorResult<T> + Send + Sync>>;
24
25pub type ChannelSender = Arc<Sender<Weak<Channel>>>;
26
27pub struct Comms;
31const COMMS_MSG_SIZE: usize = 32;
33
34pub(crate) enum CommsMsg {
35 DeclareExchange {
36 exchange: String,
37 declare: DeclareExchange,
38 },
39 RequestChannel(ChannelSender),
40}
41
42impl Comms {
43 pub async fn declare_exchange(exchange: String, declare: DeclareExchange) {
45 let sender = Self::channel_comms().0;
46 log::debug!("Sending {exchange} declaration to the rabbit loop");
47 if let Err(err) = sender
48 .send(CommsMsg::DeclareExchange { exchange, declare })
49 .await
50 {
51 log::error!("Declare exchange internal comms is broken: {err}");
52 std::process::exit(-1);
53 }
54 }
55
56 fn channel_comms() -> (
59 &'static Arc<Sender<CommsMsg>>,
60 &'static Arc<Mutex<Option<Receiver<CommsMsg>>>>,
61 ) {
62 lazy_static::lazy_static! {
63 static ref COMMS: (Arc<Sender<CommsMsg>>, Arc<Mutex<Option<Receiver<CommsMsg>>>>) = {
64 let (tx, rx) = channel(COMMS_MSG_SIZE);
65 (Arc::new(tx), Arc::new(Mutex::new(Some(rx))))
66 };
67 }
68 (&COMMS.0, &COMMS.1)
69 }
70
71 pub(crate) fn get_channel_comms() -> Arc<Sender<CommsMsg>> {
73 Self::channel_comms().0.clone()
74 }
75
76 pub(crate) fn create_channel_channel() -> (Arc<Sender<Weak<Channel>>>, Receiver<Weak<Channel>>)
78 {
79 let (tx, rx) = channel(2);
80 (Arc::new(tx), rx)
81 }
82
83 pub fn configure(config: Config) -> anyhow::Result<()> {
86 let rt = Runtime::tokio()?;
87 let spawner = rt.clone();
88 spawner.spawn(Box::pin(async move {
89 let mut msg_receiver = {
91 log::debug!("Taking the channel requester from the global area");
92 let singleton = Self::channel_comms().1.clone();
93 let mut channel_receiver = singleton.lock().await;
94 if let Some(cr) = channel_receiver.take() {
95 cr
96 } else {
97 log::error!("Fatal error. No channel receiver found. Is the Comms::configure called the second time?");
98 std::process::exit(1);
99 }
100 };
101 log::debug!("Channel requester taken, we can start the rabbit loop");
102 let mut connection: Option<Connection> = None;
103 let mut connection_attempt = 0;
104 let mut declare_exchanges = HashMap::new();
105
106 let mut channels = channels_ring::Channels::new();
107 let mut is_connecting = false;
108 loop {
109 let mut channel_sender = Vec::with_capacity(COMMS_MSG_SIZE);
110 let mut msgs = Vec::with_capacity(COMMS_MSG_SIZE);
111 let _ = msg_receiver.recv_many(&mut msgs, COMMS_MSG_SIZE).await;
112 for msg in msgs.into_iter() {
113 match msg {
114 CommsMsg::DeclareExchange { exchange, declare } => {
115 log::trace!("Received a new exchange declaration for {exchange}");
116 declare_exchanges.insert(exchange, declare);
117 }
118 CommsMsg::RequestChannel(cs) => {
119 log::trace!("There is a request for a channel");
120 channel_sender.push(cs);
121 }
122 }
123 }
124 if channel_sender.is_empty() {
125 log::debug!("No channel requesters yet, going back waiting");
126 continue;
127 }
128 loop {
130 if let Some(conn) = connection.take() {
132 log::debug!("Validating an existing connection");
134 'connection: loop {
135 match conn.status().state() {
136 ConnectionState::Initial | ConnectionState::Connecting | ConnectionState::Reconnecting => {
137 log::debug!("Connecting is in progress");
138 rt.sleep(std::time::Duration::from_millis(100)).await;
140 }
141 ConnectionState::Connected => {
142 if is_connecting {
144 log::info!("Connection to RabbitMQ established");
145 is_connecting = false;
146 } else {
147 log::debug!("RabbitMQ is already connected");
148 }
149 if !declare_exchanges.is_empty() {
150 log::debug!("There are {} exchanges to declare", declare_exchanges.len());
151 match channels.create_channel(&conn).await {
152 Ok(channel) => {
153 while !declare_exchanges.is_empty() {
155 let mut done = None;
156 for (exchange, declare) in declare_exchanges.iter() {
157 log::debug!("Running exchange declaration for '{exchange}'");
158 if let Err(err) = declare(channel.clone()).await {
159 log::error!("Failed to declare an exchange: {err}");
160 continue 'connection;
161 }
162 log::debug!("Exchange '{exchange}' declared");
163 done = Some(exchange.clone());
164 break;
165 }
166 if let Some(exchange) = done {
167 declare_exchanges.remove(&exchange);
168 }
169 }
170 }
171 Err(err) => {
172 log::error!("Connection to rabbit failed, reconnecting: {err}");
174 }
175 }
176 }
177 connection = Some(conn);
178 log::debug!("Connection initialised");
179 break;
180 }
181 ConnectionState::Closing |
182 ConnectionState::Closed |
183 ConnectionState::Error => {
184 log::warn!("Failed to connect to the rabbit server, will try to reconnect");
185 log::trace!("Sleeping for {} seconds", config.reconnect_delay.as_secs_f64());
186 rt.sleep(config.reconnect_delay).await;
187 break;
188 }
189 }
190 }
191 } else {
192 log::debug!("There is no connection yet");
193 }
194 if let Some(conn) = connection.take() {
196 log::debug!("Connection exist, getting channels");
198 match channels.create_channels(channel_sender.len(), &conn).await {
199 Ok(channels) => {
200 log::debug!("Channels are created, sending them to the individual requesters");
201 for (cs, channel) in channel_sender.drain(..).zip(channels) {
202 let channel = Arc::downgrade(&channel);
203 if let Err(err) = cs.send(channel).await {
204 log::error!("Fatal error. Failed to send the channel back to the requester: {err}");
205 std::process::exit(1);
206 }
207 }
208 connection = Some(conn);
209 break;
210 }
211 Err(err) => {
212 log::error!("Connection to rabbit failed, reconnecting: {err}");
214 }
215 }
216 } else {
217 log::debug!("Closing any existing channels if any");
219 channels.try_close().await; log::debug!("No connection, attempting to connect [{connection_attempt}]",);
222 let mut properties = ConnectionProperties::default()
223 .with_connection_name(config.name.clone().into());
224 properties
225 .client_properties
226 .insert("channel_max".into(), AMQPValue::ShortUInt(MAX_CHANNELS as ShortUInt));
227 let addr = config.address[connection_attempt % config.address.len()].as_ref();
228 connection_attempt += 1;
229 let con = Connection::connect(addr, properties).await;
230 match con {
231 Ok(con) => {
232 log::info!("Connecting to RabbitMQ");
234 connection = Some(con);
235 }
236 Err(err) => {
237 log::error!("Failed to connect: {err}");
238 log::debug!("Sleeping for {} seconds", config.reconnect_delay.as_secs_f64());
239 rt.sleep(config.reconnect_delay).await;
240 }
241 }
242 }
243 }
244 }
245 }));
246 Ok(())
247 }
248}
249
250#[async_trait::async_trait]
253pub(crate) trait RabbitDispatcher: Sync + Send {
254 type Object;
255 async fn dispatcher(&self, channel: &Channel) -> anyhow::Result<Self::Object>;
257 async fn channel_setup(&self, _channel: &Channel) -> anyhow::Result<()> {
258 Ok(())
259 }
260 async fn start_dispatch(
261 &self,
262 mut channel: Option<Weak<Channel>>,
263 channel_sender: &ChannelSender,
264 channel_receiver: &mut Receiver<Weak<Channel>>,
265 channel_requester: &Arc<Sender<CommsMsg>>,
266 ) -> (Self::Object, Weak<Channel>) {
267 let mut setup_channel = false;
268 loop {
269 let channel = if let Some(channel) = channel.take() {
271 channel
272 } else {
273 if let Err(err) = channel_requester
275 .send(CommsMsg::RequestChannel(channel_sender.clone()))
276 .await
277 {
278 log::error!("Fatal internal error. Failed to request a new channel: {err}");
279 std::process::exit(1);
280 }
281 if let Some(channel) = channel_receiver.recv().await {
283 log::trace!("Channel received");
284 setup_channel = true;
285 channel
286 } else {
287 log::error!("Fatal internal error. Failed to receive a new channel");
288 std::process::exit(1);
289 }
290 };
291 let channel = match channel.upgrade() {
293 None => {
294 log::trace!("No channel, we are going to wait for a new one");
295 continue;
296 }
297 Some(channel) => channel,
298 };
299
300 if setup_channel {
301 log::trace!("Setting up the channel");
302 if let Err(err) = self.channel_setup(&channel).await {
303 log::error!("Failed to setup the channel: {err}");
304 continue;
305 }
306 log::trace!("Channel setup done");
307 }
308
309 log::trace!("Dispatching the operation");
310 match self.dispatcher(channel.as_ref()).await {
311 Ok(object) => {
312 log::trace!("Operation is dispatched");
313 return (object, Arc::downgrade(&channel));
314 }
315 Err(err) => {
316 log::error!("Failed to failed to dispatch the operation: {}", err);
317 continue;
318 }
319 }
320 }
321 }
322}
323
324mod channels_ring;