Skip to content
This repository was archived by the owner on Apr 29, 2022. It is now read-only.

Commit a9d80da

Browse files
author
Anton Vorontsov
committed
Finished making batch message handlers.
1 parent f15618b commit a9d80da

File tree

5 files changed

+124
-57
lines changed

5 files changed

+124
-57
lines changed

examples/Examples.BatchMessageHandler/AnotherCustomBatchMessageHandler.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
using System;
21
using System.Collections.Generic;
2+
using System.Threading;
33
using System.Threading.Tasks;
44
using Microsoft.Extensions.Logging;
5-
using RabbitMQ.Client.Core.DependencyInjection.BatchMessageHandlers;
65
using RabbitMQ.Client.Core.DependencyInjection.Models;
76

87
namespace Examples.BatchMessageHandler
98
{
10-
public class AnotherCustomBatchMessageHandler : BaseBatchMessageHandler
9+
public class AnotherCustomBatchMessageHandler : RabbitMQ.Client.Core.DependencyInjection.BatchMessageHandlers.BatchMessageHandler
1110
{
1211
readonly ILogger<AnotherCustomBatchMessageHandler> _logger;
1312

@@ -19,15 +18,17 @@ public AnotherCustomBatchMessageHandler(
1918
_logger = logger;
2019
}
2120

22-
protected override TimeSpan Period { get; set; } = TimeSpan.FromSeconds(10);
23-
2421
protected override ushort PrefetchCount { get; set; } = 5;
2522

2623
protected override string QueueName { get; set; } = "another.queue.name";
2724

28-
protected override Task HandleMessages()
25+
protected override Task HandleMessage(IEnumerable<string> messages, CancellationToken cancellationToken)
2926
{
30-
_logger.LogInformation($"Handling from {typeof(AnotherCustomBatchMessageHandler)} messages");
27+
_logger.LogInformation("Handling a batch of messages.");
28+
foreach (var message in messages)
29+
{
30+
_logger.LogInformation(message);
31+
}
3132
return Task.CompletedTask;
3233
}
3334
}

examples/Examples.BatchMessageHandler/CustomBatchMessageHandler.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Threading;
35
using System.Threading.Tasks;
46
using Microsoft.Extensions.Logging;
57
using RabbitMQ.Client.Core.DependencyInjection.BatchMessageHandlers;
@@ -18,16 +20,19 @@ public CustomBatchMessageHandler(
1820
{
1921
_logger = logger;
2022
}
21-
22-
protected override TimeSpan Period { get; set; } = TimeSpan.FromMinutes(10);
2323

24-
protected override ushort PrefetchCount { get; set; } = 5;
24+
protected override ushort PrefetchCount { get; set; } = 3;
2525

2626
protected override string QueueName { get; set; } = "queue.name";
2727

28-
protected override Task HandleMessages()
28+
protected override Task HandleMessages(IEnumerable<ReadOnlyMemory<byte>> messages, CancellationToken cancellationToken)
2929
{
30-
_logger.LogInformation("Handling messages");
30+
_logger.LogInformation("Handling a batch of messages.");
31+
foreach (var message in messages)
32+
{
33+
var stringifiedMessage = Encoding.UTF8.GetString(message.ToArray());
34+
_logger.LogInformation(stringifiedMessage);
35+
}
3136
return Task.CompletedTask;
3237
}
3338
}

examples/Examples.BatchMessageHandler/Program.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ public static async Task Main()
2323
services.AddBatchMessageHandler<CustomBatchMessageHandler>(hostContext.Configuration.GetSection("RabbitMq"));
2424

2525
// Second one - passing configuration instance.
26-
// var rabbitMqConfiguration = new RabbitMqClientOptions
27-
// {
28-
// HostName = "127.0.0.1",
29-
// Port = 5672,
30-
// UserName = "guest",
31-
// Password = "guest"
32-
// };
33-
// services.AddBatchMessageHandler<AnotherCustomBatchMessageHandler>(rabbitMqConfiguration);
26+
var rabbitMqConfiguration = new RabbitMqClientOptions
27+
{
28+
HostName = "127.0.0.1",
29+
Port = 5672,
30+
UserName = "guest",
31+
Password = "guest"
32+
};
33+
services.AddBatchMessageHandler<AnotherCustomBatchMessageHandler>(rabbitMqConfiguration);
3434
})
3535
.ConfigureLogging((hostingContext, logging) =>
3636
{
Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Linq;
4-
using System.Text;
55
using System.Threading;
66
using System.Threading.Tasks;
77
using Microsoft.Extensions.Hosting;
@@ -14,21 +14,38 @@
1414

1515
namespace RabbitMQ.Client.Core.DependencyInjection.BatchMessageHandlers
1616
{
17+
/// <summary>
18+
/// A message handler that handles messages in batches.
19+
/// </summary>
1720
public abstract class BaseBatchMessageHandler : IHostedService, IDisposable
1821
{
19-
protected virtual TimeSpan DueTo { get; set; } = TimeSpan.Zero;
22+
/// <summary>
23+
/// A connection which is in use by batch message handler.
24+
/// </summary>
25+
protected IConnection Connection { get; private set; }
2026

21-
protected abstract TimeSpan Period { get; set; }
22-
27+
/// <summary>
28+
/// A channel that has been created using the connection.
29+
/// </summary>
30+
protected IModel Channel { get; private set; }
31+
32+
/// <summary>
33+
/// Prefetch size value that can be overriden.
34+
/// </summary>
2335
protected virtual uint PrefetchSize { get; set; } = 0;
2436

37+
/// <summary>
38+
/// Queue name which will be read by that batch message handler.
39+
/// </summary>
2540
protected abstract string QueueName { get; set; }
2641

42+
/// <summary>
43+
/// Prefetch count value (batch size).
44+
/// </summary>
2745
protected abstract ushort PrefetchCount { get; set; }
2846

2947
readonly RabbitMqClientOptions _clientOptions;
3048
readonly ILogger<BaseBatchMessageHandler> _logger;
31-
Timer _timer;
3249

3350
protected BaseBatchMessageHandler(
3451
IEnumerable<BatchConsumerConnectionOptions> batchConsumerConnectionOptions,
@@ -47,12 +64,28 @@ protected BaseBatchMessageHandler(
4764
public Task StartAsync(CancellationToken cancellationToken)
4865
{
4966
ValidateProperties();
50-
_logger.LogInformation("BatchMessageHandler has been started.");
51-
_timer = new Timer(
52-
async state => await StartPeriodicJob(cancellationToken),
53-
null,
54-
DueTo,
55-
Period);
67+
_logger.LogInformation($"Batch message handler {GetType()} has been started.");
68+
Connection = RabbitMqFactoryExtensions.CreateRabbitMqConnection(_clientOptions);
69+
Channel = Connection.CreateModel();
70+
Channel.BasicQos(PrefetchSize, PrefetchCount, false);
71+
72+
var messages = new ConcurrentBag<BasicDeliverEventArgs>();
73+
var consumer = new AsyncEventingBasicConsumer(Channel);
74+
consumer.Received += async (sender, eventArgs) =>
75+
{
76+
messages.Add(eventArgs);
77+
if (messages.Count < PrefetchCount)
78+
{
79+
return;
80+
}
81+
82+
var byteMessages = messages.Select(x => x.Body).ToList();
83+
await HandleMessages(byteMessages, cancellationToken);
84+
var latestDeliveryTag = messages.Max(x => x.DeliveryTag);
85+
messages.Clear();
86+
Channel.BasicAck(latestDeliveryTag, true);
87+
};
88+
Channel.BasicConsume(queue: QueueName, autoAck: false, consumer: consumer);
5689
return Task.CompletedTask;
5790
}
5891

@@ -69,40 +102,24 @@ void ValidateProperties()
69102
}
70103
}
71104

72-
async Task StartPeriodicJob(CancellationToken cancellationToken)
73-
{
74-
while (!cancellationToken.IsCancellationRequested)
75-
{
76-
using var connection = RabbitMqFactoryExtensions.CreateRabbitMqConnection(_clientOptions);
77-
using var channel = connection.CreateModel();
78-
79-
channel.BasicQos(PrefetchSize, PrefetchCount, false);
80-
81-
var consumer = new AsyncEventingBasicConsumer(channel);
82-
consumer.Received += async (sender, eventArgs) => await HandleMessageReceivingEvent(eventArgs);
83-
channel.BasicConsume(queue: QueueName, autoAck: false, consumer: consumer);
84-
}
85-
}
86-
87-
async Task HandleMessageReceivingEvent(BasicDeliverEventArgs eventArgs)
88-
{
89-
var message = Encoding.UTF8.GetString(eventArgs.Body.ToArray());
90-
_logger.LogInformation($"A new message was received with deliveryTag {eventArgs.DeliveryTag}.");
91-
_logger.LogInformation(message);
92-
}
93-
94-
protected abstract Task HandleMessages();
105+
/// <summary>
106+
/// Handle a batch of messages.
107+
/// </summary>
108+
/// <param name="messages">A collection of messages as bytes.</param>
109+
/// <param name="cancellationToken">Cancellation token.</param>
110+
/// <returns></returns>
111+
protected abstract Task HandleMessages(IEnumerable<ReadOnlyMemory<byte>> messages, CancellationToken cancellationToken);
95112

96113
public Task StopAsync(CancellationToken cancellationToken)
97114
{
98-
_logger.LogInformation("BatchMessageHandler has been stopped.");
99-
_timer?.Change(Timeout.Infinite, 0);
115+
_logger.LogInformation($"Batch message handler {GetType()} has been stopped.");
100116
return Task.CompletedTask;
101117
}
102118

103119
public void Dispose()
104120
{
105-
_timer?.Dispose();
121+
Connection?.Dispose();
122+
Channel?.Dispose();
106123
}
107124
}
108125
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Logging;
8+
using RabbitMQ.Client.Core.DependencyInjection.Models;
9+
10+
namespace RabbitMQ.Client.Core.DependencyInjection.BatchMessageHandlers
11+
{
12+
/// <summary>
13+
/// Batch message handler that handles messages and passes them into HandleMessage method as strings.
14+
/// </summary>
15+
public abstract class BatchMessageHandler : BaseBatchMessageHandler
16+
{
17+
protected BatchMessageHandler(
18+
IEnumerable<BatchConsumerConnectionOptions> batchConsumerConnectionOptions,
19+
ILogger<BatchMessageHandler> logger)
20+
: base(batchConsumerConnectionOptions, logger)
21+
{
22+
}
23+
24+
/// <summary>
25+
/// Handle a batch of messages.
26+
/// </summary>
27+
/// <param name="messages">A collection of messages as bytes.</param>
28+
/// <param name="cancellationToken">Cancellation token.</param>
29+
/// <returns></returns>
30+
protected override async Task HandleMessages(IEnumerable<ReadOnlyMemory<byte>> messages, CancellationToken cancellationToken)
31+
{
32+
var decodedMessages = messages.Select(x => Encoding.UTF8.GetString(x.ToArray()));
33+
await HandleMessage(decodedMessages, cancellationToken);
34+
}
35+
36+
/// <summary>
37+
/// Handle a batch of decoded messages.
38+
/// </summary>
39+
/// <param name="messages">A collection of messages.</param>
40+
/// <param name="cancellationToken">Cancellation token.</param>
41+
/// <returns></returns>
42+
protected abstract Task HandleMessage(IEnumerable<string> messages, CancellationToken cancellationToken);
43+
}
44+
}

0 commit comments

Comments
 (0)