init
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using RabbitMQ.Client;
|
||||
using RabbitMQ.Client.Events;
|
||||
using RabbitMQ.Client.Exceptions;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace DouyinApi.EventBus
|
||||
{
|
||||
/// <summary>
|
||||
/// RabbitMQ持久连接
|
||||
/// </summary>
|
||||
public class RabbitMQPersistentConnection
|
||||
: IRabbitMQPersistentConnection
|
||||
{
|
||||
private readonly IConnectionFactory _connectionFactory;
|
||||
private readonly ILogger<RabbitMQPersistentConnection> _logger;
|
||||
private readonly int _retryCount;
|
||||
IConnection _connection;
|
||||
bool _disposed;
|
||||
|
||||
object sync_root = new object();
|
||||
|
||||
public RabbitMQPersistentConnection(IConnectionFactory connectionFactory, ILogger<RabbitMQPersistentConnection> logger,
|
||||
int retryCount = 5)
|
||||
{
|
||||
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_retryCount = retryCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已连接
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connection != null && _connection.IsOpen && !_disposed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建Model
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IModel CreateModel()
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
throw new InvalidOperationException("No RabbitMQ connections are available to perform this action");
|
||||
}
|
||||
|
||||
return _connection.CreateModel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
try
|
||||
{
|
||||
_connection.Dispose();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.LogCritical(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool TryConnect()
|
||||
{
|
||||
_logger.LogInformation("RabbitMQ Client is trying to connect");
|
||||
|
||||
lock (sync_root)
|
||||
{
|
||||
var policy = RetryPolicy.Handle<SocketException>()
|
||||
.Or<BrokerUnreachableException>()
|
||||
.WaitAndRetry(_retryCount,
|
||||
retryAttempt =>
|
||||
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||
{
|
||||
_logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message);
|
||||
}
|
||||
);
|
||||
|
||||
policy.Execute(() =>
|
||||
{
|
||||
_connection = _connectionFactory
|
||||
.CreateConnection();
|
||||
});
|
||||
|
||||
if (IsConnected)
|
||||
{
|
||||
_connection.ConnectionShutdown += OnConnectionShutdown;
|
||||
_connection.CallbackException += OnCallbackException;
|
||||
_connection.ConnectionBlocked += OnConnectionBlocked;
|
||||
|
||||
_logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogCritical("FATAL ERROR: RabbitMQ connections could not be created and opened");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接被阻断
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnConnectionBlocked(object sender, ConnectionBlockedEventArgs e)
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
_logger.LogWarning("A RabbitMQ connection is shutdown. Trying to re-connect...");
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接出现异常
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void OnCallbackException(object sender, CallbackExceptionEventArgs e)
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
_logger.LogWarning("A RabbitMQ connection throw exception. Trying to re-connect...");
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接被关闭
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="reason"></param>
|
||||
void OnConnectionShutdown(object sender, ShutdownEventArgs reason)
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
_logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect...");
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布消息
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exchangeName"></param>
|
||||
/// <param name="routingKey"></param>
|
||||
public void PublishMessage(string message, string exchangeName, string routingKey)
|
||||
{
|
||||
using var channel = CreateModel();
|
||||
channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct, true);
|
||||
var body = Encoding.UTF8.GetBytes(message);
|
||||
channel.BasicPublish(exchange: exchangeName, routingKey: routingKey, basicProperties: null, body: body);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 订阅消息
|
||||
/// </summary>
|
||||
/// <param name="queueName"></param>
|
||||
public void StartConsuming(string queueName)
|
||||
{
|
||||
using var channel = CreateModel();
|
||||
channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
|
||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
||||
consumer.Received += new AsyncEventHandler<BasicDeliverEventArgs>(
|
||||
async (a, b) =>
|
||||
{
|
||||
var Headers = b.BasicProperties.Headers;
|
||||
var msgBody = b.Body.ToArray();
|
||||
var message = Encoding.UTF8.GetString(msgBody);
|
||||
await Task.CompletedTask;
|
||||
Console.WriteLine("Received message: {0}", message);
|
||||
|
||||
//bool Dealresult = await Dealer(b.Exchange, b.RoutingKey, msgBody, Headers);
|
||||
//if (Dealresult) channel.BasicAck(b.DeliveryTag, false);
|
||||
//else channel.BasicNack(b.DeliveryTag, false, true);
|
||||
}
|
||||
);
|
||||
|
||||
channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
|
||||
|
||||
Console.WriteLine("Consuming messages...");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user