From f2efe02be4189cb7566831fb03b1b27a57eb6770 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 24 Aug 2020 11:49:46 +0300 Subject: [PATCH 01/35] Batch publish under transaction added into the RabbitMQ connection. --- Frends.Community.RabbitMQ/Definitions.cs | 7 ++ .../Frends.Community.RabbitMQ.csproj | 2 + .../Frends.Community.RabbitMQ.nuspec | 2 +- .../MessageCompressor.cs | 35 +++++++++ Frends.Community.RabbitMQ/RabbitMQTask.cs | 76 ++++++++++++------- Frends.Community.RabbitMQ/packages.config | 1 + 6 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 Frends.Community.RabbitMQ/MessageCompressor.cs diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index 49cf7ed..d248619 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using RabbitMQ.Client; namespace Frends.Community.RabbitMQ { @@ -116,6 +117,10 @@ public WriteInputParams() /// [DisplayName(@"Host name")] [DisplayFormat(DataFormatString = "Text")] + /// + /// Amount of messages in the buffer which will be sent over messaging queue as a chunk. + /// + public string WriteMessageCount { get; set; } public string HostName { get; set; } /// /// Use URI instead of a hostname @@ -135,6 +140,7 @@ public WriteInputParams() [DefaultValue(true)] [DisplayName(@"Set durable option when creating queue")] public bool Durable { get; set; } + } public class WriteInputParamsString @@ -151,6 +157,7 @@ public WriteInputParamsString() [DisplayName(@"Data")] [DisplayFormat(DataFormatString = "Text")] public string Data { get; set; } + /// /// Name of the exchange /// diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 2847eb5..746e762 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -41,6 +41,7 @@ + @@ -50,6 +51,7 @@ + diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec index abc5e97..48f29e7 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec @@ -2,7 +2,7 @@ Frends.Community.RabbitMQ - 1.4.0 + 1.5.0 FRENDS RabbitMQ Task HiQ Poland diff --git a/Frends.Community.RabbitMQ/MessageCompressor.cs b/Frends.Community.RabbitMQ/MessageCompressor.cs new file mode 100644 index 0000000..b6a2368 --- /dev/null +++ b/Frends.Community.RabbitMQ/MessageCompressor.cs @@ -0,0 +1,35 @@ +using System.IO; +using System; +using System.IO; +using System.IO.Compression; + +namespace Frends.Community.RabbitMQ +{ + public class MessageCompresser + { + var compressedFileStream = new MemoryStream(); + using (compressedFileStream) + { + //compressedFileStream.Seek(0, SeekOrigin.Begin); + using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, false)) + { + foreach (var caseAttachmentModel in archiveDataSet) + { + //Create a zip entry for each attachment + var zipEntry = zipArchive.CreateEntry(caseAttachmentModel.name); + + //Get the stream of the attachment + using (var originalFileStream = new MemoryStream(caseAttachmentModel.body)) + { + using (var zipEntryStream = zipEntry.Open()) + { + //Copy the attachment stream to the zip entry stream + originalFileStream.CopyTo(zipEntryStream); + } + } + } + } + } + zipthis = compressedFileStream.ToArray(); + } +} \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index d15a8f7..42519c2 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -1,6 +1,5 @@ using RabbitMQ.Client; using System; -using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Linq; @@ -14,7 +13,7 @@ public class RabbitMQTask { private static IConnection _connection = null; private static IModel _channel = null; - + private static void OpenConnectionIfClosed(string hostName, bool connectWithURI) { //close connection if hostname has changed @@ -23,7 +22,7 @@ private static void OpenConnectionIfClosed(string hostName, bool connectWithURI) CloseConnection(); } - if (_connection == null || _connection.IsOpen == false) + if (_connection == null || !_connection.IsOpen) { var factory = new ConnectionFactory(); @@ -53,8 +52,8 @@ public static void CloseConnection() if (_channel != null) { _channel.Close(); + _channel.Dispose(); } - if (_connection != null) { _connection.Close(); @@ -62,38 +61,60 @@ public static void CloseConnection() } /// - /// Writes message to a queue + /// Writes messages into a queue with batch publish. All messages are under transaction. If one the message failes all messages will be rolled back. /// /// - public static bool WriteMessage([PropertyTab]WriteInputParams inputParams) + public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { - OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - - if (inputParams.Create) + try { - _channel.QueueDeclare(queue: inputParams.QueueName, - durable: inputParams.Durable, - exclusive: false, - autoDelete: false, - arguments: null); + OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - } + if (inputParams.Create && _channel == null || _channel.IsClosed) + { + _channel.QueueDeclare(queue: inputParams.QueueName, + durable: inputParams.Durable, + exclusive: false, + autoDelete: false, + arguments: null); + } - IBasicProperties basicProperties = null; - if (inputParams.Durable == true) - { + IBasicProperties basicProperties = null; - basicProperties = _channel.CreateBasicProperties(); - basicProperties.Persistent = true; + if (inputParams.Durable == true) + { + basicProperties = _channel.CreateBasicProperties(); + basicProperties.Persistent = true; + } + + if (inputParams.WriteMessageCount != null && + _channel.MessageCount(inputParams.QueueName) >= int.Parse(inputParams.WriteMessageCount)) + { + _channel.TxSelect(); + _channel.ConfirmSelect(); + IBasicPublishBatch batch = _channel.CreateBasicPublishBatch(); + batch.Publish(); + _channel.TxCommit(); + _channel.CreateBasicPublishBatch(); + if (_channel.MessageCount(inputParams.QueueName) > 0) + _channel.TxRollback(); + return true; + } + else + { + _channel.BasicPublish(exchange: + inputParams.ExchangeName, + routingKey: inputParams.RoutingKey, + basicProperties: basicProperties, + body: inputParams.Data); + return false; + } + } + finally + { + //CloseConnection(); } - - _channel.BasicPublish(exchange: inputParams.ExchangeName, - routingKey: inputParams.RoutingKey, - basicProperties: basicProperties, - body: inputParams.Data); - - return true; } /// @@ -116,7 +137,6 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP }; return WriteMessage(wip); - } /// diff --git a/Frends.Community.RabbitMQ/packages.config b/Frends.Community.RabbitMQ/packages.config index 8cb3d9d..157f190 100644 --- a/Frends.Community.RabbitMQ/packages.config +++ b/Frends.Community.RabbitMQ/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file From ef49c1666ad8f446955d4f487ef36286fb523d39 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 24 Aug 2020 11:53:02 +0300 Subject: [PATCH 02/35] Documentation addon --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e04fad6..a647d5a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Tasks | ExchangeName | string | Name of the exchange | sampleExchange | | RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| WriteMessageCount | string | Amount of messages in the buffer which will be sent over messaging queue as a batch. | 20 | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | | Create | bool | True to declare queue before writing | False to not declare it| | Durable | bool | Set durable option when creating queue | From 81f26debb949aef1ef0968a4dbe52ce88c204d7a Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 24 Aug 2020 15:43:35 +0300 Subject: [PATCH 03/35] Refactored project structure --- Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 746e762..9af2575 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -51,7 +51,7 @@ - + @@ -61,4 +61,4 @@ - \ No newline at end of file + From be7d23a4084c43faf66d7a11324c1f6fc91d10ea Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 24 Aug 2020 15:50:10 +0300 Subject: [PATCH 04/35] Refactored project structure --- Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 9af2575..1f48171 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -41,7 +41,7 @@ - + From c6b7e49be647ca6cfe7aab63a8f698cffad58861 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Tue, 25 Aug 2020 13:44:30 +0300 Subject: [PATCH 05/35] Refactoring of the code --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 42519c2..fa00877 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -92,10 +92,8 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { _channel.TxSelect(); _channel.ConfirmSelect(); - IBasicPublishBatch batch = _channel.CreateBasicPublishBatch(); - batch.Publish(); + _channel.CreateBasicPublishBatch().Publish(); _channel.TxCommit(); - _channel.CreateBasicPublishBatch(); if (_channel.MessageCount(inputParams.QueueName) > 0) _channel.TxRollback(); return true; From 6a2b6a3742a0559baf4cd584340e168d2941b4fd Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Wed, 26 Aug 2020 13:28:17 +0300 Subject: [PATCH 06/35] Refactoring of the code --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 48 +++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index fa00877..28b5b9a 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -66,17 +66,16 @@ public static void CloseConnection() /// public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { - try - { - OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - if (inputParams.Create && _channel == null || _channel.IsClosed) + if (inputParams.Create) { _channel.QueueDeclare(queue: inputParams.QueueName, durable: inputParams.Durable, exclusive: false, autoDelete: false, arguments: null); + _channel.ConfirmSelect(); } IBasicProperties basicProperties = null; @@ -86,33 +85,48 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) basicProperties = _channel.CreateBasicProperties(); basicProperties.Persistent = true; } - + if (inputParams.WriteMessageCount != null && _channel.MessageCount(inputParams.QueueName) >= int.Parse(inputParams.WriteMessageCount)) { - _channel.TxSelect(); - _channel.ConfirmSelect(); - _channel.CreateBasicPublishBatch().Publish(); - _channel.TxCommit(); - if (_channel.MessageCount(inputParams.QueueName) > 0) + try + { + _channel.TxSelect(); + _channel.CreateBasicPublishBatch().Add( + exchange: inputParams.ExchangeName, + routingKey: inputParams.RoutingKey, + mandatory: true, + properties: basicProperties, + body: inputParams.Data); + _channel.CreateBasicPublishBatch().Publish(); + _channel.TxCommit(); + if (_channel.MessageCount(inputParams.QueueName) > 0) + { + _channel.TxRollback(); + return false; + } + return true; + } + catch (Exception exception) + { _channel.TxRollback(); - return true; + throw exception; + } } - - else + else if (inputParams.WriteMessageCount != null || int.Parse(inputParams.WriteMessageCount) == 1) { _channel.BasicPublish(exchange: inputParams.ExchangeName, routingKey: inputParams.RoutingKey, basicProperties: basicProperties, body: inputParams.Data); + return true; + } + else + { return false; } - } - finally - { //CloseConnection(); - } } /// From 497e2e9212a07ac26def639c892e5b137c290ebf Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Thu, 27 Aug 2020 09:52:23 +0300 Subject: [PATCH 07/35] Refactored connection pool and channels. --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 156 +++++++++++----------- 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 28b5b9a..6e4c301 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Text; using System.Linq; +using System.Runtime.InteropServices; namespace Frends.Community.RabbitMQ { @@ -11,43 +12,33 @@ namespace Frends.Community.RabbitMQ /// public class RabbitMQTask { - private static IConnection _connection = null; - private static IModel _channel = null; + private static readonly ConnectionFactory Factory = new ConnectionFactory(); - private static void OpenConnectionIfClosed(string hostName, bool connectWithURI) + private static IConnection OpenConnectionIfClosed(string hostName, bool connectWithURI) { - //close connection if hostname has changed - if(_connection!=null && _connection.Endpoint.HostName != hostName) + lock (Factory) { - CloseConnection(); - } - - if (_connection == null || !_connection.IsOpen) - { - var factory = new ConnectionFactory(); - - if (connectWithURI) - { - factory.Uri = new Uri(hostName); - } - else + IConnection _connection = null; { - factory.HostName = hostName; + if (connectWithURI) + { + Factory.Uri = new Uri(hostName); + } + else + { + Factory.HostName = hostName; + } + _connection = Factory.CreateConnection(); } - - _connection = factory.CreateConnection(); - } - - if (_channel == null || _channel.IsClosed) - { - _channel = _connection.CreateModel(); + + return _connection; } } /// /// Closes connection and channel to RabbitMQ /// - public static void CloseConnection() + public static void CloseConnection(IModel _channel, IConnection _connection) { if (_channel != null) { @@ -66,8 +57,10 @@ public static void CloseConnection() /// public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { - OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - + IConnection _connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IModel _channel = _connection.CreateModel(); + try + { if (inputParams.Create) { _channel.QueueDeclare(queue: inputParams.QueueName, @@ -105,6 +98,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) _channel.TxRollback(); return false; } + return true; } catch (Exception exception) @@ -113,7 +107,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) throw exception; } } - else if (inputParams.WriteMessageCount != null || int.Parse(inputParams.WriteMessageCount) == 1) + else if (inputParams.WriteMessageCount != null || int.Parse(inputParams.WriteMessageCount) == 1) { _channel.BasicPublish(exchange: inputParams.ExchangeName, @@ -126,7 +120,13 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { return false; } - //CloseConnection(); + } + finally + { + CloseConnection(_channel, _connection); + } + + } /// @@ -158,62 +158,68 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP /// JSON structure with message contents public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) { - Output output = new Output(); - - OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - - //channel.QueueDeclare(queue: inputParams.QueueName, - // durable: false, - // exclusive: false, - // autoDelete: false, - // arguments: null); - - while (inputParams.ReadMessageCount-- > 0) + IConnection _connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IModel _channel = _connection.CreateModel(); + try { - var rcvMessage = _channel.BasicGet(queue: inputParams.QueueName, autoAck: inputParams.AutoAck == ReadAckType.AutoAck); - if (rcvMessage != null) - { - output.Messages.Add(new Message { Data = Convert.ToBase64String(rcvMessage.Body), MessagesCount = rcvMessage.MessageCount, DeliveryTag = rcvMessage.DeliveryTag }); - } - //break the loop if no more messagages are present - else + Output output = new Output(); + + while (inputParams.ReadMessageCount-- > 0) { - break; + var rcvMessage = _channel.BasicGet(queue: inputParams.QueueName, + autoAck: inputParams.AutoAck == ReadAckType.AutoAck); + if (rcvMessage != null) + { + output.Messages.Add(new Message + { + Data = Convert.ToBase64String(rcvMessage.Body), MessagesCount = rcvMessage.MessageCount, + DeliveryTag = rcvMessage.DeliveryTag + }); + } + //break the loop if no more messagages are present + else + { + break; + } } - } - // Auto acking - if (inputParams.AutoAck != ReadAckType.AutoAck && inputParams.AutoAck != ReadAckType.ManualAck) - { - ManualAckType ackType = ManualAckType.NackAndRequeue; - - switch (inputParams.AutoAck) + // Auto acking + if (inputParams.AutoAck != ReadAckType.AutoAck && inputParams.AutoAck != ReadAckType.ManualAck) { - case ReadAckType.AutoNack: - ackType = ManualAckType.Nack; - break; + ManualAckType ackType = ManualAckType.NackAndRequeue; - case ReadAckType.AutoNackAndRequeue: - ackType = ManualAckType.NackAndRequeue; - break; + switch (inputParams.AutoAck) + { + case ReadAckType.AutoNack: + ackType = ManualAckType.Nack; + break; + case ReadAckType.AutoNackAndRequeue: + ackType = ManualAckType.NackAndRequeue; + break; - case ReadAckType.AutoReject: - ackType = ManualAckType.Reject; - break; - case ReadAckType.AutoRejectAndRequeue: - ackType = ManualAckType.RejectAndRequeue; - break; - } + case ReadAckType.AutoReject: + ackType = ManualAckType.Reject; + break; - foreach (var message in output.Messages) - { - AcknowledgeMessage(ackType, message.DeliveryTag); + case ReadAckType.AutoRejectAndRequeue: + ackType = ManualAckType.RejectAndRequeue; + break; + } + + foreach (var message in output.Messages) + { + AcknowledgeMessage(_channel, ackType, message.DeliveryTag); + } } + + return output; + } + finally + { + CloseConnection(_channel, _connection); } - - return output; } /// @@ -241,7 +247,7 @@ public static OutputString ReadMessageString([PropertyTab]ReadInputParams inputP /// /// /// - public static void AcknowledgeMessage(ManualAckType ackType, ulong deliveryTag) + public static void AcknowledgeMessage(IModel _channel, ManualAckType ackType, ulong deliveryTag) { if (_channel == null) { From 33e64dc38f909996fefc5c6fa4c0b6d0bedccfa5 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Thu, 27 Aug 2020 09:55:08 +0300 Subject: [PATCH 08/35] Removed unnecessary compression of the messages --- .../MessageCompressor.cs | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 Frends.Community.RabbitMQ/MessageCompressor.cs diff --git a/Frends.Community.RabbitMQ/MessageCompressor.cs b/Frends.Community.RabbitMQ/MessageCompressor.cs deleted file mode 100644 index b6a2368..0000000 --- a/Frends.Community.RabbitMQ/MessageCompressor.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.IO; -using System; -using System.IO; -using System.IO.Compression; - -namespace Frends.Community.RabbitMQ -{ - public class MessageCompresser - { - var compressedFileStream = new MemoryStream(); - using (compressedFileStream) - { - //compressedFileStream.Seek(0, SeekOrigin.Begin); - using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, false)) - { - foreach (var caseAttachmentModel in archiveDataSet) - { - //Create a zip entry for each attachment - var zipEntry = zipArchive.CreateEntry(caseAttachmentModel.name); - - //Get the stream of the attachment - using (var originalFileStream = new MemoryStream(caseAttachmentModel.body)) - { - using (var zipEntryStream = zipEntry.Open()) - { - //Copy the attachment stream to the zip entry stream - originalFileStream.CopyTo(zipEntryStream); - } - } - } - } - } - zipthis = compressedFileStream.ToArray(); - } -} \ No newline at end of file From e02c5d224ee2e5b70fe8e18f3c8aab1cdfd1e71e Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Thu, 27 Aug 2020 09:58:03 +0300 Subject: [PATCH 09/35] Removed unnecessary imports --- Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 1f48171..31a8c80 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -41,7 +41,6 @@ - @@ -51,7 +50,6 @@ - From c1027d76ab6af5b3bbeff8683f2298a9db740a90 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Thu, 27 Aug 2020 10:02:26 +0300 Subject: [PATCH 10/35] Refactored UI definitions --- Frends.Community.RabbitMQ/Definitions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index d248619..8047ec1 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -117,11 +117,14 @@ public WriteInputParams() /// [DisplayName(@"Host name")] [DisplayFormat(DataFormatString = "Text")] + public string HostName { get; set; } /// - /// Amount of messages in the buffer which will be sent over messaging queue as a chunk. + /// Amount of messages in the buffer under trasaction which will be sent over the messaging channel as a chunk. /// + /// [DefaultValue(1)] + [DisplayName(@"Write message count")] public string WriteMessageCount { get; set; } - public string HostName { get; set; } + /// /// Use URI instead of a hostname /// From cf4c15ee65ee73dd46396661b37abb7e96cac7f8 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Thu, 27 Aug 2020 11:06:05 +0300 Subject: [PATCH 11/35] Refactored the transaction commit cycle --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 65 ++++++++++++++--------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 6e4c301..78fba9f 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -79,47 +79,60 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) basicProperties.Persistent = true; } - if (inputParams.WriteMessageCount != null && - _channel.MessageCount(inputParams.QueueName) >= int.Parse(inputParams.WriteMessageCount)) + + if (inputParams.WriteMessageCount == null || + inputParams.WriteMessageCount != null && int.Parse(inputParams.WriteMessageCount) == 1) { - try + _channel.BasicPublish(exchange: + inputParams.ExchangeName, + routingKey: inputParams.RoutingKey, + basicProperties: basicProperties, + body: inputParams.Data); + return true; + } + else + { + // Add message into a memory based on producer write capability. + if (inputParams.WriteMessageCount != null && + _channel.MessageCount(inputParams.QueueName) <= int.Parse(inputParams.WriteMessageCount)) { - _channel.TxSelect(); _channel.CreateBasicPublishBatch().Add( exchange: inputParams.ExchangeName, routingKey: inputParams.RoutingKey, mandatory: true, properties: basicProperties, body: inputParams.Data); - _channel.CreateBasicPublishBatch().Publish(); - _channel.TxCommit(); - if (_channel.MessageCount(inputParams.QueueName) > 0) + return false; + } + + // Commit under transaction when all of the messages have been received for the producer. + if (inputParams.WriteMessageCount != null && + _channel.MessageCount(inputParams.QueueName) == int.Parse(inputParams.WriteMessageCount)) + { + try + { + _channel.TxSelect(); + _channel.CreateBasicPublishBatch().Publish(); + _channel.TxCommit(); + if (_channel.MessageCount(inputParams.QueueName) > 0) + { + _channel.TxRollback(); + return false; + } + return true; + } + catch (Exception exception) { _channel.TxRollback(); - return false; + throw exception; } - - return true; } - catch (Exception exception) + + else { - _channel.TxRollback(); - throw exception; + return false; } } - else if (inputParams.WriteMessageCount != null || int.Parse(inputParams.WriteMessageCount) == 1) - { - _channel.BasicPublish(exchange: - inputParams.ExchangeName, - routingKey: inputParams.RoutingKey, - basicProperties: basicProperties, - body: inputParams.Data); - return true; - } - else - { - return false; - } } finally { From 9d1731a18c0e4ded606806e40718552e4f0fd8c9 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 11:01:31 +0300 Subject: [PATCH 12/35] Refactoring the scope and boundary of the global transaction. --- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 18 ++-- Frends.Community.RabbitMQ/Definitions.cs | 13 ++- Frends.Community.RabbitMQ/RabbitMQTask.cs | 87 ++++++++++++-------- 3 files changed, 72 insertions(+), 46 deletions(-) diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index f4a1b3f..0b6ddff 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -63,7 +63,7 @@ public void TestWriteRead() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue" }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString()}); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1 }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } @@ -75,7 +75,7 @@ public void TestReadWithAck10() DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue" }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString()}); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000 }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } @@ -87,7 +87,7 @@ public void TestReadNoAck10() DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue" }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString() }); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10 }); @@ -100,7 +100,7 @@ public void TestWriteReadWithURI() DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); @@ -114,7 +114,7 @@ public void TestReadWithAck10WithURI() CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, ProcessExecutionId = Guid.NewGuid().ToString() }); } @@ -131,7 +131,7 @@ public void TestReadNoAck10WithURI() CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, ProcessExecutionId = Guid.NewGuid().ToString() }); } var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); @@ -148,7 +148,7 @@ public void TestWriteToNonExistingQueue() Exception xx = null; try { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, ProcessExecutionId = Guid.NewGuid().ToString() }); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); @@ -166,7 +166,7 @@ public void TestWriteToExistingQueue() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, Durable = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } @@ -177,7 +177,7 @@ public void TestWriteToExistingExchange() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, ExchangeName = "exchange", ConnectWithURI = false, Create = false, Durable = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, ExchangeName = "exchange", ConnectWithURI = false, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index 8047ec1..6cfd7b0 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -124,7 +124,12 @@ public WriteInputParams() /// [DefaultValue(1)] [DisplayName(@"Write message count")] public string WriteMessageCount { get; set; } - + /// + /// Process execution id from the system + /// + /// [DefaultValue(#process.executionid)] + [DisplayName(@"Process execution id")] + public string ProcessExecutionId { get; set; } /// /// Use URI instead of a hostname /// @@ -189,6 +194,12 @@ public WriteInputParamsString() [DisplayFormat(DataFormatString = "Text")] public string HostName { get; set; } /// + /// Process execution id from the system + /// + /// [DefaultValue(#process.executionid)] + [DisplayName(@"Process execution id")] + public string ProcessExecutionId { get; set; } + /// /// Use URI instead of a hostname /// [DefaultValue(false)] diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 78fba9f..f884a68 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -1,9 +1,10 @@ using RabbitMQ.Client; using System; +using System.Collections.Concurrent; using System.ComponentModel; using System.Text; using System.Linq; -using System.Runtime.InteropServices; +using System.Threading; namespace Frends.Community.RabbitMQ { @@ -14,11 +15,15 @@ public class RabbitMQTask { private static readonly ConnectionFactory Factory = new ConnectionFactory(); + private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); + + private static ReaderWriterLock ReaderWriterLock = new ReaderWriterLock(); + private static IConnection OpenConnectionIfClosed(string hostName, bool connectWithURI) { lock (Factory) { - IConnection _connection = null; + IConnection connection = null; { if (connectWithURI) { @@ -28,26 +33,37 @@ private static IConnection OpenConnectionIfClosed(string hostName, bool connectW { Factory.HostName = hostName; } - _connection = Factory.CreateConnection(); + connection = Factory.CreateConnection(); } - return _connection; + return connection; } } + private static IBasicPublishBatch CreateBasicPublishBatch(String processExecutionId, IModel channel) + { + IBasicPublishBatch basicPublishBatch = channel.CreateBasicPublishBatch(); + return ConcurrentDictionary.GetOrAdd(processExecutionId, basicPublishBatch); + } + + private static void DeleteBasicPublishBatch(String processExecutionId, IBasicPublishBatch channel) + { + ConcurrentDictionary.TryRemove(processExecutionId, out channel); + } + /// /// Closes connection and channel to RabbitMQ /// - public static void CloseConnection(IModel _channel, IConnection _connection) + public static void CloseConnection(IModel channel, IConnection connection) { - if (_channel != null) + if (channel != null) { - _channel.Close(); - _channel.Dispose(); + channel.Close(); + channel.Dispose(); } - if (_connection != null) + if (connection != null) { - _connection.Close(); + connection.Close(); } } @@ -57,33 +73,32 @@ public static void CloseConnection(IModel _channel, IConnection _connection) /// public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { - IConnection _connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - IModel _channel = _connection.CreateModel(); + IConnection connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IModel channel = connection.CreateModel(); try { if (inputParams.Create) { - _channel.QueueDeclare(queue: inputParams.QueueName, + channel.QueueDeclare(queue: inputParams.QueueName, durable: inputParams.Durable, exclusive: false, autoDelete: false, arguments: null); - _channel.ConfirmSelect(); + channel.ConfirmSelect(); } IBasicProperties basicProperties = null; if (inputParams.Durable == true) { - basicProperties = _channel.CreateBasicProperties(); + basicProperties = channel.CreateBasicProperties(); basicProperties.Persistent = true; } - if (inputParams.WriteMessageCount == null || inputParams.WriteMessageCount != null && int.Parse(inputParams.WriteMessageCount) == 1) { - _channel.BasicPublish(exchange: + channel.BasicPublish(exchange: inputParams.ExchangeName, routingKey: inputParams.RoutingKey, basicProperties: basicProperties, @@ -94,9 +109,9 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { // Add message into a memory based on producer write capability. if (inputParams.WriteMessageCount != null && - _channel.MessageCount(inputParams.QueueName) <= int.Parse(inputParams.WriteMessageCount)) + channel.MessageCount(inputParams.QueueName) <= int.Parse(inputParams.WriteMessageCount)) { - _channel.CreateBasicPublishBatch().Add( + CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( exchange: inputParams.ExchangeName, routingKey: inputParams.RoutingKey, mandatory: true, @@ -104,26 +119,27 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) body: inputParams.Data); return false; } - + // Commit under transaction when all of the messages have been received for the producer. if (inputParams.WriteMessageCount != null && - _channel.MessageCount(inputParams.QueueName) == int.Parse(inputParams.WriteMessageCount)) + channel.MessageCount(inputParams.QueueName) == int.Parse(inputParams.WriteMessageCount)) { try { - _channel.TxSelect(); - _channel.CreateBasicPublishBatch().Publish(); - _channel.TxCommit(); - if (_channel.MessageCount(inputParams.QueueName) > 0) + channel.TxSelect(); + CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); + channel.TxCommit(); + + if (channel.MessageCount(inputParams.QueueName) > 0) { - _channel.TxRollback(); + channel.TxRollback(); return false; } return true; } catch (Exception exception) { - _channel.TxRollback(); + channel.TxRollback(); throw exception; } } @@ -136,10 +152,8 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) } finally { - CloseConnection(_channel, _connection); + CloseConnection(channel, connection); } - - } /// @@ -158,7 +172,8 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP HostName = inputParams.HostName, ExchangeName = inputParams.ExchangeName, QueueName = inputParams.QueueName, - RoutingKey = inputParams.RoutingKey + RoutingKey = inputParams.RoutingKey, + ProcessExecutionId = inputParams.ProcessExecutionId }; return WriteMessage(wip); @@ -171,15 +186,15 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP /// JSON structure with message contents public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) { - IConnection _connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); - IModel _channel = _connection.CreateModel(); + IConnection connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IModel channel = connection.CreateModel(); try { Output output = new Output(); while (inputParams.ReadMessageCount-- > 0) { - var rcvMessage = _channel.BasicGet(queue: inputParams.QueueName, + var rcvMessage = channel.BasicGet(queue: inputParams.QueueName, autoAck: inputParams.AutoAck == ReadAckType.AutoAck); if (rcvMessage != null) { @@ -223,7 +238,7 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) foreach (var message in output.Messages) { - AcknowledgeMessage(_channel, ackType, message.DeliveryTag); + AcknowledgeMessage(channel, ackType, message.DeliveryTag); } } @@ -231,7 +246,7 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) } finally { - CloseConnection(_channel, _connection); + CloseConnection(channel, connection); } } From c7f48d8f86e8de35cceb69a9a4f10b18c5661934 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 11:06:58 +0300 Subject: [PATCH 13/35] Refactoring the scope and boundary of the global transaction. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a647d5a..dc38070 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Tasks | RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | | WriteMessageCount | string | Amount of messages in the buffer which will be sent over messaging queue as a batch. | 20 | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | | Create | bool | True to declare queue before writing | False to not declare it| | Durable | bool | Set durable option when creating queue | @@ -44,6 +45,7 @@ Tasks | RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | | Create | bool | True to declare queue before writing | False to not declare it| | Durable | bool | Set durable option when creating queue | From acdac3eea940352f75c9fd1f3f058f11a64bda8a Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 11:09:42 +0300 Subject: [PATCH 14/35] Refactoring the scope and boundary of the global transaction. --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index f884a68..9c06ad8 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -17,8 +17,6 @@ public class RabbitMQTask private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); - private static ReaderWriterLock ReaderWriterLock = new ReaderWriterLock(); - private static IConnection OpenConnectionIfClosed(string hostName, bool connectWithURI) { lock (Factory) From 95eb252124973c845269fbe9e59cefe07764a32d Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 11:10:42 +0300 Subject: [PATCH 15/35] Refactoring the scope and boundary of the global transaction. --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 9c06ad8..b1ae781 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -17,7 +17,7 @@ public class RabbitMQTask private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); - private static IConnection OpenConnectionIfClosed(string hostName, bool connectWithURI) + private static IConnection CreateConnection(string hostName, bool connectWithURI) { lock (Factory) { @@ -71,7 +71,7 @@ public static void CloseConnection(IModel channel, IConnection connection) /// public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { - IConnection connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); try { @@ -184,7 +184,7 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP /// JSON structure with message contents public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) { - IConnection connection = OpenConnectionIfClosed(inputParams.HostName, inputParams.ConnectWithURI); + IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); try { From c25e9bb4dcd24f04d3eae2a6b07502dd92b4cebe Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 11:43:54 +0300 Subject: [PATCH 16/35] Refactoring the scope and boundary of the global transaction. --- Frends.Community.RabbitMQ/Definitions.cs | 9 +++------ Frends.Community.RabbitMQ/RabbitMQTask.cs | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index 6cfd7b0..de3f93b 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -2,10 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RabbitMQ.Client; namespace Frends.Community.RabbitMQ { @@ -121,9 +117,10 @@ public WriteInputParams() /// /// Amount of messages in the buffer under trasaction which will be sent over the messaging channel as a chunk. /// - /// [DefaultValue(1)] + [DefaultValue(1)] + [DisplayFormat(DataFormatString = "Text")] [DisplayName(@"Write message count")] - public string WriteMessageCount { get; set; } + public int WriteMessageCount { get; set; } /// /// Process execution id from the system /// diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index b1ae781..494e1fe 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -93,8 +93,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) basicProperties.Persistent = true; } - if (inputParams.WriteMessageCount == null || - inputParams.WriteMessageCount != null && int.Parse(inputParams.WriteMessageCount) == 1) + if (inputParams.WriteMessageCount <= 1) { channel.BasicPublish(exchange: inputParams.ExchangeName, @@ -106,8 +105,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) else { // Add message into a memory based on producer write capability. - if (inputParams.WriteMessageCount != null && - channel.MessageCount(inputParams.QueueName) <= int.Parse(inputParams.WriteMessageCount)) + if (channel.MessageCount(inputParams.QueueName) <= inputParams.WriteMessageCount) { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( exchange: inputParams.ExchangeName, @@ -119,8 +117,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) } // Commit under transaction when all of the messages have been received for the producer. - if (inputParams.WriteMessageCount != null && - channel.MessageCount(inputParams.QueueName) == int.Parse(inputParams.WriteMessageCount)) + if (channel.MessageCount(inputParams.QueueName) == inputParams.WriteMessageCount) { try { From bd32afb970d5355da4dac3a721ab8a65f13fe20e Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Fri, 28 Aug 2020 13:33:16 +0300 Subject: [PATCH 17/35] Refactoring the scope and boundary of the global transaction. --- Frends.Community.RabbitMQ/Definitions.cs | 7 + Frends.Community.RabbitMQ/RabbitMQTask.cs | 162 ++++++++++++++++------ 2 files changed, 127 insertions(+), 42 deletions(-) diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index de3f93b..c8e8b2b 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -191,6 +191,13 @@ public WriteInputParamsString() [DisplayFormat(DataFormatString = "Text")] public string HostName { get; set; } /// + /// Amount of messages in the buffer under trasaction which will be sent over the messaging channel as a chunk. + /// + [DefaultValue(1)] + [DisplayFormat(DataFormatString = "Text")] + [DisplayName(@"Write message count")] + public int WriteMessageCount { get; set; } + /// /// Process execution id from the system /// /// [DefaultValue(#process.executionid)] diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 494e1fe..6754420 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -4,7 +4,6 @@ using System.ComponentModel; using System.Text; using System.Linq; -using System.Threading; namespace Frends.Community.RabbitMQ { @@ -40,19 +39,19 @@ private static IConnection CreateConnection(string hostName, bool connectWithURI private static IBasicPublishBatch CreateBasicPublishBatch(String processExecutionId, IModel channel) { - IBasicPublishBatch basicPublishBatch = channel.CreateBasicPublishBatch(); - return ConcurrentDictionary.GetOrAdd(processExecutionId, basicPublishBatch); + return ConcurrentDictionary.GetOrAdd(processExecutionId, + (x) => channel.CreateBasicPublishBatch()); } - private static void DeleteBasicPublishBatch(String processExecutionId, IBasicPublishBatch channel) + private static void DeleteBasicPublishBatch(String processExecutionId) { - ConcurrentDictionary.TryRemove(processExecutionId, out channel); + ConcurrentDictionary.TryRemove(processExecutionId, out var _); } /// /// Closes connection and channel to RabbitMQ /// - public static void CloseConnection(IModel channel, IConnection connection) + private static void CloseConnection(IModel channel, IConnection connection) { if (channel != null) { @@ -63,10 +62,29 @@ public static void CloseConnection(IModel channel, IConnection connection) { connection.Close(); } + } + + /// + /// Closes connection and channel to RabbitMQ + /// + private static void CloseBatchConnection(IModel channel, IConnection connection, string processExecutionId) + { + if (!ConcurrentDictionary.ContainsKey(processExecutionId)) + { + if (channel != null) + { + channel.Close(); + channel.Dispose(); + } + if (connection != null) + { + connection.Close(); + } + } } /// - /// Writes messages into a queue with batch publish. All messages are under transaction. If one the message failes all messages will be rolled back. + /// Writes messages into a queue with simple publish. Message is not under transaction. No rollback of failed messages. /// /// public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) @@ -102,52 +120,87 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) body: inputParams.Data); return true; } - else + + return false; + } + finally + { + CloseConnection(channel, connection); + } + } + + /// + /// Writes messages into a queue with batch publish. All messages are under transaction. If one the message failes all messages will be rolled back. + /// + /// + public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) + { + IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); + IModel channel = connection.CreateModel(); + try + { + if (inputParams.Create) { - // Add message into a memory based on producer write capability. - if (channel.MessageCount(inputParams.QueueName) <= inputParams.WriteMessageCount) - { - CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( - exchange: inputParams.ExchangeName, - routingKey: inputParams.RoutingKey, - mandatory: true, - properties: basicProperties, - body: inputParams.Data); - return false; - } + channel.QueueDeclare(queue: inputParams.QueueName, + durable: inputParams.Durable, + exclusive: false, + autoDelete: false, + arguments: null); + channel.ConfirmSelect(); + } - // Commit under transaction when all of the messages have been received for the producer. - if (channel.MessageCount(inputParams.QueueName) == inputParams.WriteMessageCount) + IBasicProperties basicProperties = null; + + if (inputParams.Durable == true) + { + basicProperties = channel.CreateBasicProperties(); + basicProperties.Persistent = true; + } + + // Add message into a memory based on producer write capability. + if (channel.MessageCount(inputParams.QueueName) <= inputParams.WriteMessageCount) + { + CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( + exchange: inputParams.ExchangeName, + routingKey: inputParams.RoutingKey, + mandatory: true, + properties: basicProperties, + body: inputParams.Data); + return false; + } + + // Commit under transaction when all of the messages have been received for the producer. + if (channel.MessageCount(inputParams.QueueName) == inputParams.WriteMessageCount) + { + try { - try - { - channel.TxSelect(); - CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); - channel.TxCommit(); - - if (channel.MessageCount(inputParams.QueueName) > 0) - { - channel.TxRollback(); - return false; - } - return true; - } - catch (Exception exception) + channel.TxSelect(); + CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); + channel.TxCommit(); + + if (channel.MessageCount(inputParams.QueueName) > 0) { channel.TxRollback(); - throw exception; + return false; } + + DeleteBasicPublishBatch(inputParams.ProcessExecutionId); + return true; } - - else + catch (Exception exception) { - return false; + channel.TxRollback(); + throw exception; } } + else + { + return false; + } } finally { - CloseConnection(channel, connection); + CloseBatchConnection(channel, connection, inputParams.ProcessExecutionId); } } @@ -164,16 +217,41 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP Create = inputParams.Create, Data = Encoding.UTF8.GetBytes(inputParams.Data), Durable = inputParams.Durable, + WriteMessageCount = inputParams.WriteMessageCount, + ProcessExecutionId = inputParams.ProcessExecutionId, HostName = inputParams.HostName, ExchangeName = inputParams.ExchangeName, QueueName = inputParams.QueueName, - RoutingKey = inputParams.RoutingKey, - ProcessExecutionId = inputParams.ProcessExecutionId + RoutingKey = inputParams.RoutingKey }; return WriteMessage(wip); } + /// + /// Writes message to a queue in batch. Message is a string and there is internal conversion from string to byte[] using UTF8 encoding + /// + /// + /// + public static bool WriteTextMessageBatch([PropertyTab]WriteInputParamsString inputParams) + { + WriteInputParams wip = new WriteInputParams + { + ConnectWithURI = inputParams.ConnectWithURI, + Create = inputParams.Create, + Data = Encoding.UTF8.GetBytes(inputParams.Data), + Durable = inputParams.Durable, + WriteMessageCount = inputParams.WriteMessageCount, + ProcessExecutionId = inputParams.ProcessExecutionId, + HostName = inputParams.HostName, + ExchangeName = inputParams.ExchangeName, + QueueName = inputParams.QueueName, + RoutingKey = inputParams.RoutingKey + }; + + return WriteBatchMessage(wip); + } + /// /// Reads message(s) from a queue. Returns JSON structure with message contents. Message data is byte[] encoded to base64 string /// From e88f45ceb7bc4eb8e20ff0c5dcf27b27c86af56b Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 31 Aug 2020 09:27:02 +0300 Subject: [PATCH 18/35] https://github.com/CommunityHiQ/Frends.Community.RabbitMQ/pull/13#discussion_r478966945 --- Frends.Community.RabbitMQ/Definitions.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index c8e8b2b..89d2a89 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -124,7 +124,8 @@ public WriteInputParams() /// /// Process execution id from the system /// - /// [DefaultValue(#process.executionid)] + [DefaultValue("#process.executionid")] + [DisplayFormat(DataFormatString = "Expression")] [DisplayName(@"Process execution id")] public string ProcessExecutionId { get; set; } /// @@ -200,7 +201,8 @@ public WriteInputParamsString() /// /// Process execution id from the system /// - /// [DefaultValue(#process.executionid)] + [DefaultValue("#process.executionid")] + [DisplayFormat(DataFormatString = "Expression")] [DisplayName(@"Process execution id")] public string ProcessExecutionId { get; set; } /// From 41767a7e4e5e21fc2fdfeecdc803a8c443b1ee5c Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 31 Aug 2020 10:30:59 +0300 Subject: [PATCH 19/35] https://github.com/CommunityHiQ/Frends.Community.RabbitMQ/pull/13#discussion_r479947576 --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 27 ++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 6754420..84acf2d 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -36,6 +36,27 @@ private static IConnection CreateConnection(string hostName, bool connectWithURI return connection; } } + + private static IConnection CreateBatchConnection(string hostName, bool connectWithURI) + { + lock (Factory) + { + IConnection connection = null; + { + if (connectWithURI) + { + Factory.Uri = new Uri(hostName); + } + else + { + Factory.HostName = hostName; + } + connection = Factory.CreateConnection(); + } + + return connection; + } + } private static IBasicPublishBatch CreateBasicPublishBatch(String processExecutionId, IModel channel) { @@ -91,6 +112,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); + try { if (inputParams.Create) @@ -100,7 +122,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) exclusive: false, autoDelete: false, arguments: null); - channel.ConfirmSelect(); + channel.ConfirmSelect(); } IBasicProperties basicProperties = null; @@ -146,7 +168,7 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) exclusive: false, autoDelete: false, arguments: null); - channel.ConfirmSelect(); + channel.TxSelect(); } IBasicProperties basicProperties = null; @@ -174,7 +196,6 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) { try { - channel.TxSelect(); CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); channel.TxCommit(); From 12f6a8db3a5e69d7f0bbfd04fc6ca7a388a227f7 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 31 Aug 2020 10:52:50 +0300 Subject: [PATCH 20/35] https://github.com/CommunityHiQ/Frends.Community.RabbitMQ/pull/13#discussion_r479958478 --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 84acf2d..3a18727 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -15,7 +15,8 @@ public class RabbitMQTask private static readonly ConnectionFactory Factory = new ConnectionFactory(); private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); - + private static ConcurrentDictionary BatchChannels = new ConcurrentDictionary(); + private static IConnection CreateConnection(string hostName, bool connectWithURI) { lock (Factory) @@ -37,7 +38,7 @@ private static IConnection CreateConnection(string hostName, bool connectWithURI } } - private static IConnection CreateBatchConnection(string hostName, bool connectWithURI) + private static IConnection CreateBatchConnection(string processExecutionId, string hostName, bool connectWithURI) { lock (Factory) { @@ -53,8 +54,8 @@ private static IConnection CreateBatchConnection(string hostName, bool connectWi } connection = Factory.CreateConnection(); } - - return connection; + return BatchChannels.GetOrAdd(processExecutionId, + (x) => connection); } } @@ -100,6 +101,8 @@ private static void CloseBatchConnection(IModel channel, IConnection connection, if (connection != null) { connection.Close(); + BatchChannels.TryRemove(processExecutionId, out var _); + connection = null; } } } @@ -157,7 +160,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) /// public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) { - IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); + IConnection connection = CreateBatchConnection(inputParams.ProcessExecutionId, inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); try { From 5a1513bd46146fd86ebb02d0aed5e1bc2cc36882 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Mon, 31 Aug 2020 10:55:46 +0300 Subject: [PATCH 21/35] https://github.com/CommunityHiQ/Frends.Community.RabbitMQ/pull/13#discussion_r479958478 --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 3a18727..d50ba9e 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -42,23 +42,11 @@ private static IConnection CreateBatchConnection(string processExecutionId, stri { lock (Factory) { - IConnection connection = null; - { - if (connectWithURI) - { - Factory.Uri = new Uri(hostName); - } - else - { - Factory.HostName = hostName; - } - connection = Factory.CreateConnection(); - } return BatchChannels.GetOrAdd(processExecutionId, - (x) => connection); + (x) => CreateConnection(hostName, connectWithURI)); } } - + private static IBasicPublishBatch CreateBasicPublishBatch(String processExecutionId, IModel channel) { return ConcurrentDictionary.GetOrAdd(processExecutionId, From 7ca21b341a546bf35001baf3d1ec7fb6beec9fa6 Mon Sep 17 00:00:00 2001 From: Leinonen Ilkka Date: Wed, 2 Sep 2020 13:14:43 +0300 Subject: [PATCH 22/35] Rollback enhancement, rollback only when catching exception --- .../Frends.Community.RabbitMQ.Tests.csproj | 24 +++++++++++++++++++ Frends.Community.RabbitMQ/RabbitMQTask.cs | 11 +++++---- 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj diff --git a/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj new file mode 100644 index 0000000..1c7f0cb --- /dev/null +++ b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj @@ -0,0 +1,24 @@ + + + + net471 + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index d50ba9e..7e23719 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -16,7 +16,7 @@ public class RabbitMQTask private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); private static ConcurrentDictionary BatchChannels = new ConcurrentDictionary(); - + private static IConnection CreateConnection(string hostName, bool connectWithURI) { lock (Factory) @@ -189,26 +189,27 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); channel.TxCommit(); - + /** + * rollback only when exception is thrown if (channel.MessageCount(inputParams.QueueName) > 0) { channel.TxRollback(); return false; } - + */ DeleteBasicPublishBatch(inputParams.ProcessExecutionId); return true; } catch (Exception exception) { channel.TxRollback(); - throw exception; + return false; } } else { return false; - } + } } finally { From 5142a073881fca345388e3c1381a7eb7e7238444 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Tue, 29 Sep 2020 11:39:13 +0300 Subject: [PATCH 23/35] Unit test can be now easily run. --- Frends.Community.RabbitMQ.Tests/Tests.csproj | 7 + Frends.Community.RabbitMQ.Tests/UnitTests.cs | 123 +++++++------- .../packages.config | 2 + .../Frends.Community.RabbitMQ.csproj | 2 +- Frends.Community.RabbitMQ/README.md | 157 ++++++++++++++++++ 5 files changed, 225 insertions(+), 66 deletions(-) create mode 100644 Frends.Community.RabbitMQ/README.md diff --git a/Frends.Community.RabbitMQ.Tests/Tests.csproj b/Frends.Community.RabbitMQ.Tests/Tests.csproj index 7ca6c55..53e564c 100644 --- a/Frends.Community.RabbitMQ.Tests/Tests.csproj +++ b/Frends.Community.RabbitMQ.Tests/Tests.csproj @@ -1,5 +1,7 @@  + + @@ -48,6 +50,9 @@ ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + ..\packages\RabbitMQ.Client.5.1.0\lib\net451\RabbitMQ.Client.dll @@ -75,6 +80,8 @@ + + \ No newline at end of file diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index 0b6ddff..cc49747 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -1,32 +1,36 @@ using System; using System.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; using RabbitMQ.Client; +using NUnit.Framework; namespace Frends.Community.RabbitMQ.Tests { - [TestClass] + + /// + /// You will need access to RabbitMQ queue, you can create it e.g. by running + /// + /// docker run -d --hostname my-rabbit -p 9080:15672 -p 5772:5672 -e RABBITMQ_DEFAULT_USER=agent -e RABBITMQ_DEFAULT_PASS=agent123 rabbitmq:3.7-management + /// + /// In that case URI would be amqp://agent:agent123@localhost:5772 + /// + /// + + [TestFixture] + // [Ignore("RabbitMQ is not installed on build server.")] public class UnitTests { - //public const string TestURI = "amqp://user:password@hostname:port/vhost"; - public const string TestURI = "localhost"; - - [TestInitialize] - public void TestInit() - { - - //var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000 }); - //var retVal2 = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); - } + //public const string TestURI = "amqp://user:password@hostname:port/vhost"; + public string TestURI = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); /// /// Deletes test exchange and queue if it exists /// - private void DeleteExchangeAndQueue() + [TearDown] + public void DeleteExchangeAndQueue() { var factory = new ConnectionFactory(); - factory.HostName = "localhost"; + factory.Uri = new Uri(TestURI); using (var connection = factory.CreateConnection()) { @@ -41,10 +45,12 @@ private void DeleteExchangeAndQueue() /// /// Creates test exchange and queue /// - private void CreateExchangeAndQueue() + [SetUp] + public void CreateExchangeAndQueue() { var factory = new ConnectionFactory(); - factory.HostName = "localhost"; + //factory.HostName = "localhost"; + factory.Uri = new Uri(TestURI); using (var connection = factory.CreateConnection()) { @@ -57,44 +63,41 @@ private void CreateExchangeAndQueue() } } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteRead() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString()}); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1 }); + // DeleteExchangeAndQueue(); + // CreateExchangeAndQueue(); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true}); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } - [TestMethod] - [Ignore("Rabbit/*M*/Q is not installed on build server.")] + [Test] public void TestReadWithAck10() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString()}); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000 }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestReadNoAck10() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = "localhost", RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString() }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = "localhost", QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10 }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + + [Test] public void TestWriteReadWithURI() { DeleteExchangeAndQueue(); @@ -106,51 +109,47 @@ public void TestWriteReadWithURI() Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestReadWithAck10WithURI() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); } - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 10, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestReadNoAck10WithURI() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); } - - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); + + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteToNonExistingQueue() { DeleteExchangeAndQueue(); Exception xx = null; try { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); } catch (Exception x) @@ -160,48 +159,44 @@ public void TestWriteToNonExistingQueue() Assert.IsTrue(xx != null); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteToExistingQueue() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteToExistingExchange() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, ExchangeName = "exchange", ConnectWithURI = false, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, ExchangeName = "exchange", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteReadStringToQueue() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = false, Create = false, Durable = false }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] public void TestWriteReadStringToExchange() { DeleteExchangeAndQueue(); CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = false, Create = false, Durable = false }); + Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = true, Create = false, Durable = false }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = false }); + var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } @@ -209,8 +204,8 @@ public void TestWriteReadStringToExchange() /// /// Used for debugging, if connection is closed and opened for new hostname /// - [TestMethod] - [Ignore("RabbitMQ is not installed on build server.")] + [Test] + [Ignore("This test is actually used for debugging while developing task.")] public void TestChangingHostName() { DeleteExchangeAndQueue(); @@ -220,7 +215,5 @@ public void TestChangingHostName() Assert.IsTrue(true); } - - } } diff --git a/Frends.Community.RabbitMQ.Tests/packages.config b/Frends.Community.RabbitMQ.Tests/packages.config index 5d42412..dd40b67 100644 --- a/Frends.Community.RabbitMQ.Tests/packages.config +++ b/Frends.Community.RabbitMQ.Tests/packages.config @@ -3,5 +3,7 @@ + + \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 31a8c80..2847eb5 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -59,4 +59,4 @@ - + \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/README.md b/Frends.Community.RabbitMQ/README.md new file mode 100644 index 0000000..6c47b05 --- /dev/null +++ b/Frends.Community.RabbitMQ/README.md @@ -0,0 +1,157 @@ +# Frends.Community.RabbitMQ +Frends task for operating on RabbitMQ queues using AMQP 0-9-1. Supports reading and writing from queue. + +- [Installing](#installing) +- [Tasks](#tasks) + - [Write Message](#writemessage) + - [Write Message String](#writemessagestring) + - [Read Message](#readmessage) + - [Read Message String](#readmessagestring) +- [License](#license) +- [Building](#building) +- [Contributing](#contributing) +- [Change Log](#change-log) + +# Installing +You can install the task via FRENDS UI Task View or you can find the nuget package from the following nuget feed +'Nuget feed coming at later date' + +Tasks +===== + +## WriteMessage + +### Task Parameters + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | byte[] | Data to be put in message body| new byte[]{1,2,3}| +| QueueName | string | Name of the queue | sampleQueue | +| ExchangeName | string | Name of the exchange | sampleExchange | +| RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| WriteMessageCount | string | Amount of messages in the buffer which will be sent over messaging queue as a batch. | 20 | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | +| Create | bool | True to declare queue before writing | False to not declare it| +| Durable | bool | Set durable option when creating queue | + +## WriteMessageString +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | string | Data to be put in message body| "abc"| +| QueueName | string | Name of the queue | sampleQueue | +| ExchangeName | string | Name of the exchange | sampleQueue | +| RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | +| Create | bool | True to declare queue before writing | False to not declare it| +| Durable | bool | Set durable option when creating queue | + + +## ReadMessage + +### Task Parameters + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| QueueName | string | Name of the queue | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| ReadMessageCount | int | Maximum number of messages to be read from queue. It can exceed number of available messages. | 1 | +| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue,AutoReject,AutoRejectAndRequeue,ManualAck| ReadAckType.AutoAck | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | + +### Output + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Messages | List | A list of message-objects | | + +### Message-object + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | string (base64 encoded byte[]) | | | +| MessageCount | uint | | | +| DeliveryTag | ulong | | | + +### Read message sample JSON + +{"Messages":[{"Data":"AAEC","MessagesCount":0,"DeliveryTag":1}]} + +## ReadMessageString + +### Task Parameters + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| QueueName | string | Name of the queue | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| ReadMessageCount | int | Maximum number of messages to be read from queue. It can exceed number of available messages. | 1 | +| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue,AutoReject,AutoRejectAndRequeue,ManualAck| ReadAckType.AutoAck | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | + +### OutputString + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Messages | List | A list of MessageString-objects | | + + +### MessageString-object + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | string (UTF8 converted byte[]) | | | +| MessageCount | uint | | | +| DeliveryTag | ulong | | | + + + + +# License + +This project is licensed under the MIT License - see the LICENSE file for details + +# Building + +Clone a copy of the repo + +`git clone https://github.com/CommunityHiQ/Frends.Community.RabbitMQ.git` + +Restore dependencies + +`nuget restore frends.community.rabbitmq` + +Rebuild the project + +Run Tests with nunit3. Tests can be found under + +`Frends.Community.Email.Tests\bin\Release\Frends.Community.RabbitMQ.Tests.dll` + +Create a nuget package + +`nuget pack nuspec/Frends.Community.RabbitMQ.nuspec` + +# Contributing +When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. + +1. Fork the repo on GitHub +2. Clone the project to your own machine +3. Commit changes to your own branch +4. Push your work back up to your fork +5. Submit a Pull request so that we can review your changes + +NOTE: Be sure to merge the latest from "upstream" before making a pull request! + +# Change Log + +| Version | Changes | +| ---------------------| ---------------------| +| 1.0.2 | Initial version of RabbitMQ | +| 1.0.7 | Connect with URI added | +| 1.0.8 | Add Create and Durable options in WriteMessage. Remove declaring queue in ReadMessage operation | +| 1.1.0 | Fix nacking while reading multiple messages before it read same message multiple times, because of immediately nacking | +| 1.2.0 | Write to exchange, but does not implement creating exchange on fly. | +| 1.3.0 | Message persistence is set to true if durable parameter is true. | From 3e6adf7c4b4bf2c118c99da23f13b6c5b34a080a Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 4 Nov 2020 10:28:29 +0200 Subject: [PATCH 24/35] Tests can be now run against local rabbitmq in docker. --- .github/workflows/BuildAndTestOnEveryPush.yml | 28 +++++++ .github/workflows/PackAndPushAfterMerge.yml | 40 ++++++++++ .../Frends.Community.RabbitMQ.Tests.csproj | 8 +- .../Properties/AssemblyInfo.cs | 20 ----- Frends.Community.RabbitMQ.Tests/Tests.csproj | 3 +- Frends.Community.RabbitMQ.sln | 16 ++-- .../Frends.Community.RabbitMQ.csproj | 77 +++++-------------- .../Frends.Community.RabbitMQ.nuspec | 28 ------- .../FrendsTaskMetadata.json | 7 ++ .../Properties/AssemblyInfo.cs | 36 --------- Frends.Community.RabbitMQ/RabbitMQTask.cs | 2 +- 11 files changed, 108 insertions(+), 157 deletions(-) create mode 100644 .github/workflows/BuildAndTestOnEveryPush.yml create mode 100644 .github/workflows/PackAndPushAfterMerge.yml delete mode 100644 Frends.Community.RabbitMQ.Tests/Properties/AssemblyInfo.cs delete mode 100644 Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec create mode 100644 Frends.Community.RabbitMQ/FrendsTaskMetadata.json delete mode 100644 Frends.Community.RabbitMQ/Properties/AssemblyInfo.cs diff --git a/.github/workflows/BuildAndTestOnEveryPush.yml b/.github/workflows/BuildAndTestOnEveryPush.yml new file mode 100644 index 0000000..959ac9e --- /dev/null +++ b/.github/workflows/BuildAndTestOnEveryPush.yml @@ -0,0 +1,28 @@ +name: BuildAndTestOnEveryPush.yml + +on: + push: + branches-ignore: + - master + +jobs: + build: + name: Build on windows-latest + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + + - name: Build + run: dotnet build + + - name: Test + env: + EXAMPLE_ENVIROMENT_VARIABLE: ${{ secrets.EXAMPLE_ENVIROMENT_VARIABLE }} + run: dotnet test + + - name: Pack release version of task + run: dotnet pack --configuration Release --include-source + + - name: Push NuGet package to the testfeed + run: dotnet nuget push Frends.Community.RabbitMQ\bin\Release\Frends.Community.RabbitMQ.*.nupkg --api-key ${{ secrets.COMMUNITY_FEED_API_KEY }} --source https://www.myget.org/F/frends-community-test/api/v2/package --symbol-source https://www.myget.org/F/frends-community-test/symbols/api/v2/package diff --git a/.github/workflows/PackAndPushAfterMerge.yml b/.github/workflows/PackAndPushAfterMerge.yml new file mode 100644 index 0000000..4e7bd68 --- /dev/null +++ b/.github/workflows/PackAndPushAfterMerge.yml @@ -0,0 +1,40 @@ +name: PackAndPushAfterMerge + +on: + push: + branches: + - master + +jobs: + build: + name: ReleaseTheTask + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + + - name: Get version number + id: vars + shell: pwsh + run: | + $version = ([xml]($tmp = Get-Content -Path 'Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj')).SelectSingleNode("Project/PropertyGroup/Version").InnerText + echo "::set-output name=version_number::$version" + + - name: Pack release version of task + run: dotnet pack --configuration Release --include-source + + - name: Push NuGet package to the (prod) feed + run: dotnet nuget push Frends.Community.RabbitMQ\bin\Release\Frends.Community.RabbitMQ.*.nupkg --api-key ${{ secrets.COMMUNITY_FEED_API_KEY }} --source https://www.myget.org/F/frends-community/api/v2/package --symbol-source https://www.myget.org/F/frends-community/symbols/api/v2/package + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.vars.outputs.version_number }} + release_name: Release ${{ steps.vars.outputs.version_number }} + body: | + You can install the task via frends UI Task View or you can find the NuGet package from https://www.myget.org/F/frends-community/api/v2/package/Frends.Community.RabbitMQ/${{ steps.vars.outputs.version_number }} + draft: false + prerelease: false diff --git a/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj index 1c7f0cb..6cf1cb0 100644 --- a/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj +++ b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj @@ -1,15 +1,13 @@  - net471 - + net471 + false - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Frends.Community.RabbitMQ.Tests/Properties/AssemblyInfo.cs b/Frends.Community.RabbitMQ.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 9296caa..0000000 --- a/Frends.Community.RabbitMQ.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Frends.Community.RabbitMQ")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Frends.Community.RabbitMQ")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("e7570bbf-f363-43fb-9c36-61bda1349b74")] - -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Frends.Community.RabbitMQ.Tests/Tests.csproj b/Frends.Community.RabbitMQ.Tests/Tests.csproj index 53e564c..a0e9652 100644 --- a/Frends.Community.RabbitMQ.Tests/Tests.csproj +++ b/Frends.Community.RabbitMQ.Tests/Tests.csproj @@ -12,7 +12,7 @@ Properties Frends.Community.RabbitMQ.Tests Frends.Community.RabbitMQ.Tests - v4.5.2 + v4.6 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15.0 @@ -22,6 +22,7 @@ UnitTest + true diff --git a/Frends.Community.RabbitMQ.sln b/Frends.Community.RabbitMQ.sln index 50c203e..9cdde28 100644 --- a/Frends.Community.RabbitMQ.sln +++ b/Frends.Community.RabbitMQ.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.271 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30503.244 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Frends.Community.RabbitMQ", "Frends.Community.RabbitMQ\Frends.Community.RabbitMQ.csproj", "{DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frends.Community.RabbitMQ", "Frends.Community.RabbitMQ\Frends.Community.RabbitMQ.csproj", "{DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Frends.Community.RabbitMQ.Tests\Tests.csproj", "{E7570BBF-F363-43FB-9C36-61BDA1349B74}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frends.Community.RabbitMQ.Tests", "Frends.Community.RabbitMQ.Tests\Frends.Community.RabbitMQ.Tests.csproj", "{FC0A38D4-6C86-4362-B65F-EDDE7CCA5D39}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,10 +17,10 @@ Global {DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU {DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU {DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF}.Release|Any CPU.Build.0 = Release|Any CPU - {E7570BBF-F363-43FB-9C36-61BDA1349B74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7570BBF-F363-43FB-9C36-61BDA1349B74}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7570BBF-F363-43FB-9C36-61BDA1349B74}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7570BBF-F363-43FB-9C36-61BDA1349B74}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0A38D4-6C86-4362-B65F-EDDE7CCA5D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0A38D4-6C86-4362-B65F-EDDE7CCA5D39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0A38D4-6C86-4362-B65F-EDDE7CCA5D39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0A38D4-6C86-4362-B65F-EDDE7CCA5D39}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 2847eb5..08b6888 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -1,62 +1,23 @@ - - - + + - Debug - AnyCPU - {DBB2AD78-CF28-44AB-BCAC-D4B7D4035DDF} - Library - Properties - Frends.Community.RabbitMQ - Frends.Community.RabbitMQ - v4.5.2 - 512 - true + netstandard2.0;net471 + HiQ Finland + HiQ Finland + MIT + https://github.com/CommunityHiQ/Frends.Community.RabbitMQ + true + Frends + true + 1.5.1 + false - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Frends.Community.RabbitMQ.xml - - - - ..\packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.28\lib\net40\Microsoft.Diagnostics.Tracing.EventSource.dll - - - ..\packages\RabbitMQ.Client.5.1.0\lib\net451\RabbitMQ.Client.dll - - - - - - - - - - - - - - - - + - - - + + + - - \ No newline at end of file + + + diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec deleted file mode 100644 index 48f29e7..0000000 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.nuspec +++ /dev/null @@ -1,28 +0,0 @@ - - - - Frends.Community.RabbitMQ - 1.5.0 - FRENDS RabbitMQ Task - HiQ Poland - - false - FRENDS RabbitMQ Task - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/FrendsTaskMetadata.json b/Frends.Community.RabbitMQ/FrendsTaskMetadata.json new file mode 100644 index 0000000..5821b4a --- /dev/null +++ b/Frends.Community.RabbitMQ/FrendsTaskMetadata.json @@ -0,0 +1,7 @@ +{ + "Tasks": [ + { + "TaskMethod": "Frends.Community.RabbitMQ.Echo.ExecuteEcho" + } + ] +} \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/Properties/AssemblyInfo.cs b/Frends.Community.RabbitMQ/Properties/AssemblyInfo.cs deleted file mode 100644 index 2981024..0000000 --- a/Frends.Community.RabbitMQ/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Frends.RabbitMQ")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Frends.RabbitMQ")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("dbb2ad78-cf28-44ab-bcac-d4b7d4035ddf")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.6.0")] -[assembly: AssemblyFileVersion("1.0.6.0")] diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 7e23719..737f6d6 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -286,7 +286,7 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) { output.Messages.Add(new Message { - Data = Convert.ToBase64String(rcvMessage.Body), MessagesCount = rcvMessage.MessageCount, + Data = Convert.ToBase64String(rcvMessage.Body.ToArray()), MessagesCount = rcvMessage.MessageCount, DeliveryTag = rcvMessage.DeliveryTag }); } From 1d76dd2cbdf08a6c52ad0f1265d38bd59ad875dd Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 4 Nov 2020 13:03:33 +0200 Subject: [PATCH 25/35] Create BuildAndTestonEveryPushLinux --- .../workflows/BuildAndTestonEveryPushLinux | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/BuildAndTestonEveryPushLinux diff --git a/.github/workflows/BuildAndTestonEveryPushLinux b/.github/workflows/BuildAndTestonEveryPushLinux new file mode 100644 index 0000000..c6032e5 --- /dev/null +++ b/.github/workflows/BuildAndTestonEveryPushLinux @@ -0,0 +1,28 @@ +name: BuildAndTestonEveryPushLinux.yml + +on: + push: + branches-ignore: + - master + +jobs: + build: + name: Build on ubuntu-latest + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Build + run: dotnet build + + - name: Test + env: + EXAMPLE_ENVIROMENT_VARIABLE: ${{ secrets.EXAMPLE_ENVIROMENT_VARIABLE }} + run: dotnet test + + - name: Pack release version of task + run: dotnet pack --configuration Release --include-source + + - name: Push NuGet package to the testfeed + run: dotnet nuget push Frends.Community.RabbitMQ\bin\Release\Frends.Community.RabbitMQ.*.nupkg --api-key ${{ secrets.COMMUNITY_FEED_API_KEY }} --source https://www.myget.org/F/frends-community-test/api/v2/package --symbol-source https://www.myget.org/F/frends-community-test/symbols/api/v2/package From fafd0bb28c6ed5bcad8f46975d038046f293deb1 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 4 Nov 2020 13:04:00 +0200 Subject: [PATCH 26/35] Rename BuildAndTestonEveryPushLinux to BuildAndTestonEveryPushLinux.yml --- ...ldAndTestonEveryPushLinux => BuildAndTestonEveryPushLinux.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{BuildAndTestonEveryPushLinux => BuildAndTestonEveryPushLinux.yml} (100%) diff --git a/.github/workflows/BuildAndTestonEveryPushLinux b/.github/workflows/BuildAndTestonEveryPushLinux.yml similarity index 100% rename from .github/workflows/BuildAndTestonEveryPushLinux rename to .github/workflows/BuildAndTestonEveryPushLinux.yml From ce877f610086fabb7a052363c09c67dc5b5b5270 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 4 Nov 2020 13:20:17 +0200 Subject: [PATCH 27/35] Update BuildAndTestonEveryPushLinux.yml --- .github/workflows/BuildAndTestonEveryPushLinux.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/BuildAndTestonEveryPushLinux.yml b/.github/workflows/BuildAndTestonEveryPushLinux.yml index c6032e5..f522d62 100644 --- a/.github/workflows/BuildAndTestonEveryPushLinux.yml +++ b/.github/workflows/BuildAndTestonEveryPushLinux.yml @@ -9,6 +9,11 @@ jobs: build: name: Build on ubuntu-latest runs-on: ubuntu-latest + + container: + image: rabbitmq:3.7-management + options: --hostname my-rabbit -p 9080:15672 -p 5772:5672 -e RABBITMQ_DEFAULT_USER=agent -e RABBITMQ_DEFAULT_PASS=agent123 + steps: - uses: actions/checkout@v1 From d7a8154787a55d4558e2338c3c3dd60995d46c18 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 4 Nov 2020 13:28:08 +0200 Subject: [PATCH 28/35] Update BuildAndTestonEveryPushLinux.yml --- .github/workflows/BuildAndTestonEveryPushLinux.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/BuildAndTestonEveryPushLinux.yml b/.github/workflows/BuildAndTestonEveryPushLinux.yml index f522d62..9a98fb1 100644 --- a/.github/workflows/BuildAndTestonEveryPushLinux.yml +++ b/.github/workflows/BuildAndTestonEveryPushLinux.yml @@ -10,9 +10,6 @@ jobs: name: Build on ubuntu-latest runs-on: ubuntu-latest - container: - image: rabbitmq:3.7-management - options: --hostname my-rabbit -p 9080:15672 -p 5772:5672 -e RABBITMQ_DEFAULT_USER=agent -e RABBITMQ_DEFAULT_PASS=agent123 steps: From 79b2a855fb13df45701f04df3f868d62d5528a41 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Mon, 16 Nov 2020 12:04:44 +0200 Subject: [PATCH 29/35] Refactored unit tests. --- .../Frends.Community.RabbitMQ.Tests.csproj | 2 +- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 189 +++++++++++++----- .../Frends.Community.RabbitMQ.csproj | 2 +- Frends.Community.RabbitMQ/RabbitMQTask.cs | 18 +- 4 files changed, 147 insertions(+), 64 deletions(-) diff --git a/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj index 6cf1cb0..07198ea 100644 --- a/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj +++ b/Frends.Community.RabbitMQ.Tests/Frends.Community.RabbitMQ.Tests.csproj @@ -1,7 +1,7 @@  - net471 + net472 false diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index cc49747..19c98ce 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -1,7 +1,7 @@ -using System; -using System.Linq; +using NUnit.Framework; using RabbitMQ.Client; -using NUnit.Framework; +using System; +using System.Linq; namespace Frends.Community.RabbitMQ.Tests { @@ -21,7 +21,13 @@ public class UnitTests { //public const string TestURI = "amqp://user:password@hostname:port/vhost"; - public string TestURI = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); + public static string TestURI = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); + public static string TestHost = "localhost"; + + private WriteInputParams InputParameters = new WriteInputParams(); + private WriteInputParamsString inputParametersString = new WriteInputParamsString(); + private ReadInputParams OutputReadParams; + /// /// Deletes test exchange and queue if it exists @@ -49,7 +55,6 @@ public void DeleteExchangeAndQueue() public void CreateExchangeAndQueue() { var factory = new ConnectionFactory(); - //factory.HostName = "localhost"; factory.Uri = new Uri(TestURI); using (var connection = factory.CreateConnection()) @@ -61,38 +66,82 @@ public void CreateExchangeAndQueue() channel.QueueBind("queue", "exchange", routingKey: ""); } } + + InputParameters = new WriteInputParams + { + Data = new byte[] { 0, 1, 2 }, + HostName = TestHost, + RoutingKey = "queue", + QueueName = "queue", + ProcessExecutionId = Guid.NewGuid().ToString(), + ConnectWithURI = false, + Create = false, + Durable = false + }; + + + + inputParametersString = new WriteInputParamsString + { + Data = "test message", + HostName = TestHost, + RoutingKey = "queue", + QueueName = "queue", + ProcessExecutionId = Guid.NewGuid().ToString(), + ConnectWithURI = false, + Create = false, + Durable = false + }; + + OutputReadParams = new ReadInputParams + { + HostName = TestHost, + QueueName = "queue", + AutoAck = ReadAckType.AutoAck, + ReadMessageCount = 1, + ConnectWithURI = false + }; } [Test] public void TestWriteRead() { - // DeleteExchangeAndQueue(); - // CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true}); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1, ConnectWithURI = true }); + RabbitMQTask.WriteMessage(InputParameters); + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } [Test] public void TestReadWithAck10() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); + OutputReadParams.ReadMessageCount = 1000; + for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + { + InputParameters.Data = new byte[] { 0, (byte)(i * i) }; + RabbitMQTask.WriteMessage(InputParameters); + } + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } [Test] public void TestReadNoAck10() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); + InputParameters.ConnectWithURI = true; + InputParameters.HostName = TestURI; + + OutputReadParams.ReadMessageCount = 10; + OutputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; + + for (int i = 0; i < 10; i++) - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = true }); + { + InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); + RabbitMQTask.WriteMessage(InputParameters); + } + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } @@ -100,11 +149,15 @@ public void TestReadNoAck10() [Test] public void TestWriteReadWithURI() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); + InputParameters.HostName = TestURI; + InputParameters.ConnectWithURI = true; + + OutputReadParams.ConnectWithURI = true; + OutputReadParams.HostName = TestURI; - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1, ConnectWithURI = true }); + + RabbitMQTask.WriteMessage(InputParameters); + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } @@ -112,14 +165,23 @@ public void TestWriteReadWithURI() [Test] public void TestReadWithAck10WithURI() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); + InputParameters.HostName = TestURI; + InputParameters.ConnectWithURI = true; + + + OutputReadParams.ConnectWithURI = true; + OutputReadParams.HostName = TestURI; + OutputReadParams.ReadMessageCount = 10; + + for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); + InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + + RabbitMQTask.WriteMessage(InputParameters); } - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 10, ConnectWithURI = true }); + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } @@ -127,14 +189,23 @@ public void TestReadWithAck10WithURI() [Test] public void TestReadNoAck10WithURI() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); + InputParameters.HostName = TestURI; + InputParameters.ConnectWithURI = true; + + + OutputReadParams.ConnectWithURI = true; + OutputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; + OutputReadParams.HostName = TestURI; + OutputReadParams.ReadMessageCount = 10; + for (int i = 0; i < 10; i++) { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0, (byte)(i * i), (byte)i }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, ProcessExecutionId = Guid.NewGuid().ToString() }); + InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + + RabbitMQTask.WriteMessage(InputParameters); } - - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoNackAndRequeue, ReadMessageCount = 10, ConnectWithURI = true }); + + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } @@ -143,13 +214,17 @@ public void TestReadNoAck10WithURI() [Test] public void TestWriteToNonExistingQueue() { - DeleteExchangeAndQueue(); Exception xx = null; + + InputParameters.QueueName = "queue2"; // Queue won't exist, but don't create it + + OutputReadParams.QueueName = "queue2"; + try { - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + RabbitMQTask.WriteMessage(InputParameters); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + var _ = RabbitMQTask.ReadMessage(OutputReadParams); } catch (Exception x) @@ -160,43 +235,51 @@ public void TestWriteToNonExistingQueue() } [Test] - public void TestWriteToExistingQueue() + public void TestWriteToNewQueue() // pois TODO { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + + InputParameters.QueueName = "queue2"; + InputParameters.Create = true; + + OutputReadParams.QueueName = "queue2"; + + RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); + var retVal = RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } [Test] public void TestWriteToExistingExchange() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, ExchangeName = "exchange", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + + InputParameters.QueueName = null; + InputParameters.ExchangeName = "exchange"; + + RabbitMQTask.WriteMessage(InputParameters); + var retVal = RabbitMQTask.ReadMessage(OutputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } [Test] public void TestWriteReadStringToQueue() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + + RabbitMQTask.WriteMessageString(inputParametersString); + var retVal = RabbitMQTask.ReadMessageString(OutputReadParams); + Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } [Test] public void TestWriteReadStringToExchange() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = TestURI, ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = true, Create = false, Durable = false }); - var retVal = Frends.Community.RabbitMQ.RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + inputParametersString.QueueName = null; + inputParametersString.ExchangeName = "exchange"; + + RabbitMQTask.WriteMessageString(inputParametersString); + + var retVal = RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } @@ -208,10 +291,8 @@ public void TestWriteReadStringToExchange() [Ignore("This test is actually used for debugging while developing task.")] public void TestChangingHostName() { - DeleteExchangeAndQueue(); - CreateExchangeAndQueue(); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = "amqp://localhost", ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = true, Create = false, Durable = false }); - Frends.Community.RabbitMQ.RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = "localhost2", ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = false, Create = false, Durable = false }); + RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = "amqp://localhost", ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = true, Create = false, Durable = false }); + RabbitMQTask.WriteMessageString(new WriteInputParamsString { Data = "test message", HostName = "localhost2", ExchangeName = "exchange", RoutingKey = "queue", ConnectWithURI = false, Create = false, Durable = false }); Assert.IsTrue(true); } diff --git a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj index 08b6888..8b88166 100644 --- a/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj +++ b/Frends.Community.RabbitMQ/Frends.Community.RabbitMQ.csproj @@ -9,7 +9,7 @@ true Frends true - 1.5.1 + 1.5.2 false diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 737f6d6..8216f99 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -344,14 +344,16 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) public static OutputString ReadMessageString([PropertyTab]ReadInputParams inputParams) { var messages = ReadMessage(inputParams); - OutputString outString = new OutputString(); - outString.Messages = messages.Messages.Select(m => - new MessageString - { - DeliveryTag = m.DeliveryTag, - MessagesCount = m.MessagesCount, - Data = Encoding.UTF8.GetString(Convert.FromBase64String(m.Data)) - }).ToList(); + OutputString outString = new OutputString + { + Messages = messages.Messages.Select(m => + new MessageString + { + DeliveryTag = m.DeliveryTag, + MessagesCount = m.MessagesCount, + Data = Encoding.UTF8.GetString(Convert.FromBase64String(m.Data)) + }).ToList() + }; return outString; } From b13802203680f158ea052d2f20cd1e38d081e2c9 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Wed, 2 Dec 2020 13:46:00 +0200 Subject: [PATCH 30/35] Better naming. Documented batch tasks in readme. --- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 148 +++++++++---------- Frends.Community.RabbitMQ/Definitions.cs | 143 +++++++++++++++++- Frends.Community.RabbitMQ/README.md | 37 ++++- Frends.Community.RabbitMQ/RabbitMQTask.cs | 127 ++++++++-------- 4 files changed, 297 insertions(+), 158 deletions(-) diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index 19c98ce..42e7e0d 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -21,12 +21,12 @@ public class UnitTests { //public const string TestURI = "amqp://user:password@hostname:port/vhost"; - public static string TestURI = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); + public static string TestUri = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); public static string TestHost = "localhost"; - private WriteInputParams InputParameters = new WriteInputParams(); - private WriteInputParamsString inputParametersString = new WriteInputParamsString(); - private ReadInputParams OutputReadParams; + private WriteInputParams _inputParameters = new WriteInputParams(); + private WriteInputParamsString _inputParametersString = new WriteInputParamsString(); + private ReadInputParams _outputReadParams; /// @@ -35,8 +35,10 @@ public class UnitTests [TearDown] public void DeleteExchangeAndQueue() { - var factory = new ConnectionFactory(); - factory.Uri = new Uri(TestURI); + var factory = new ConnectionFactory + { + Uri = new Uri(TestUri) + }; using (var connection = factory.CreateConnection()) { @@ -54,8 +56,10 @@ public void DeleteExchangeAndQueue() [SetUp] public void CreateExchangeAndQueue() { - var factory = new ConnectionFactory(); - factory.Uri = new Uri(TestURI); + var factory = new ConnectionFactory + { + Uri = new Uri(TestUri) + }; using (var connection = factory.CreateConnection()) { @@ -67,13 +71,12 @@ public void CreateExchangeAndQueue() } } - InputParameters = new WriteInputParams + _inputParameters = new WriteInputParams { Data = new byte[] { 0, 1, 2 }, HostName = TestHost, RoutingKey = "queue", QueueName = "queue", - ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = false, Create = false, Durable = false @@ -81,19 +84,18 @@ public void CreateExchangeAndQueue() - inputParametersString = new WriteInputParamsString + _inputParametersString = new WriteInputParamsString { Data = "test message", HostName = TestHost, RoutingKey = "queue", QueueName = "queue", - ProcessExecutionId = Guid.NewGuid().ToString(), ConnectWithURI = false, Create = false, Durable = false }; - OutputReadParams = new ReadInputParams + _outputReadParams = new ReadInputParams { HostName = TestHost, QueueName = "queue", @@ -106,106 +108,106 @@ public void CreateExchangeAndQueue() [Test] public void TestWriteRead() { - RabbitMQTask.WriteMessage(InputParameters); - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + RabbitMQTask.WriteMessage(_inputParameters); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } [Test] public void TestReadWithAck10() { - OutputReadParams.ReadMessageCount = 1000; + _outputReadParams.ReadMessageCount = 1000; for (int i = 0; i < 10; i++) { - InputParameters.Data = new byte[] { 0, (byte)(i * i) }; - RabbitMQTask.WriteMessage(InputParameters); + _inputParameters.Data = new byte[] { 0, (byte)(i * i) }; + RabbitMQTask.WriteMessage(_inputParameters); } - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } [Test] public void TestReadNoAck10() { - InputParameters.ConnectWithURI = true; - InputParameters.HostName = TestURI; + _inputParameters.ConnectWithURI = true; + _inputParameters.HostName = TestUri; - OutputReadParams.ReadMessageCount = 10; - OutputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; + _outputReadParams.ReadMessageCount = 10; + _outputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; for (int i = 0; i < 10; i++) { - InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + _inputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; - RabbitMQTask.WriteMessage(InputParameters); + RabbitMQTask.WriteMessage(_inputParameters); } - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } [Test] - public void TestWriteReadWithURI() + public void TestWriteReadWithUri() { - InputParameters.HostName = TestURI; - InputParameters.ConnectWithURI = true; + _inputParameters.HostName = TestUri; + _inputParameters.ConnectWithURI = true; - OutputReadParams.ConnectWithURI = true; - OutputReadParams.HostName = TestURI; + _outputReadParams.ConnectWithURI = true; + _outputReadParams.HostName = TestUri; - RabbitMQTask.WriteMessage(InputParameters); - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + RabbitMQTask.WriteMessage(_inputParameters); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } [Test] - public void TestReadWithAck10WithURI() + public void TestReadWithAck10WithUri() { - InputParameters.HostName = TestURI; - InputParameters.ConnectWithURI = true; + _inputParameters.HostName = TestUri; + _inputParameters.ConnectWithURI = true; - OutputReadParams.ConnectWithURI = true; - OutputReadParams.HostName = TestURI; - OutputReadParams.ReadMessageCount = 10; + _outputReadParams.ConnectWithURI = true; + _outputReadParams.HostName = TestUri; + _outputReadParams.ReadMessageCount = 10; for (int i = 0; i < 10; i++) { - InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + _inputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; - RabbitMQTask.WriteMessage(InputParameters); + RabbitMQTask.WriteMessage(_inputParameters); } - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } [Test] - public void TestReadNoAck10WithURI() + public void TestReadNoAck10WithUri() { - InputParameters.HostName = TestURI; - InputParameters.ConnectWithURI = true; + _inputParameters.HostName = TestUri; + _inputParameters.ConnectWithURI = true; - OutputReadParams.ConnectWithURI = true; - OutputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; - OutputReadParams.HostName = TestURI; - OutputReadParams.ReadMessageCount = 10; + _outputReadParams.ConnectWithURI = true; + _outputReadParams.AutoAck = ReadAckType.AutoNackAndRequeue; + _outputReadParams.HostName = TestUri; + _outputReadParams.ReadMessageCount = 10; for (int i = 0; i < 10; i++) { - InputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + _inputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; - RabbitMQTask.WriteMessage(InputParameters); + RabbitMQTask.WriteMessage(_inputParameters); } - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); } @@ -216,15 +218,15 @@ public void TestWriteToNonExistingQueue() { Exception xx = null; - InputParameters.QueueName = "queue2"; // Queue won't exist, but don't create it + _inputParameters.QueueName = "queue2"; // Queue won't exist, but don't create it - OutputReadParams.QueueName = "queue2"; + _outputReadParams.QueueName = "queue2"; try { - RabbitMQTask.WriteMessage(InputParameters); + RabbitMQTask.WriteMessage(_inputParameters); - var _ = RabbitMQTask.ReadMessage(OutputReadParams); + var _ = RabbitMQTask.ReadMessage(_outputReadParams); } catch (Exception x) @@ -234,29 +236,15 @@ public void TestWriteToNonExistingQueue() Assert.IsTrue(xx != null); } - [Test] - public void TestWriteToNewQueue() // pois TODO - { - - InputParameters.QueueName = "queue2"; - InputParameters.Create = true; - - OutputReadParams.QueueName = "queue2"; - - RabbitMQTask.WriteMessage(new WriteInputParams { Data = new byte[] { 0 }, HostName = TestURI, RoutingKey = "queue", QueueName = "queue", ConnectWithURI = true, Create = false, Durable = false, ProcessExecutionId = Guid.NewGuid().ToString() }); - var retVal = RabbitMQTask.ReadMessage(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); - Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); - } - [Test] public void TestWriteToExistingExchange() { - InputParameters.QueueName = null; - InputParameters.ExchangeName = "exchange"; + _inputParameters.QueueName = null; + _inputParameters.ExchangeName = "exchange"; - RabbitMQTask.WriteMessage(InputParameters); - var retVal = RabbitMQTask.ReadMessage(OutputReadParams); + RabbitMQTask.WriteMessage(_inputParameters); + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1); } @@ -264,8 +252,8 @@ public void TestWriteToExistingExchange() public void TestWriteReadStringToQueue() { - RabbitMQTask.WriteMessageString(inputParametersString); - var retVal = RabbitMQTask.ReadMessageString(OutputReadParams); + RabbitMQTask.WriteMessageString(_inputParametersString); + var retVal = RabbitMQTask.ReadMessageString(_outputReadParams); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } @@ -274,12 +262,12 @@ public void TestWriteReadStringToQueue() public void TestWriteReadStringToExchange() { - inputParametersString.QueueName = null; - inputParametersString.ExchangeName = "exchange"; + _inputParametersString.QueueName = null; + _inputParametersString.ExchangeName = "exchange"; - RabbitMQTask.WriteMessageString(inputParametersString); + RabbitMQTask.WriteMessageString(_inputParametersString); - var retVal = RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestURI, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); + var retVal = RabbitMQTask.ReadMessageString(new ReadInputParams { HostName = TestUri, QueueName = "queue", AutoAck = ReadAckType.AutoAck, ReadMessageCount = 1000, ConnectWithURI = true }); Assert.IsTrue(retVal != null && retVal.Messages.Count() == 1 && retVal.Messages[0].Data == "test message"); } diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index 89d2a89..ce9874a 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -115,17 +115,84 @@ public WriteInputParams() [DisplayFormat(DataFormatString = "Text")] public string HostName { get; set; } /// - /// Amount of messages in the buffer under trasaction which will be sent over the messaging channel as a chunk. + /// Use URI instead of a hostname + /// + [DefaultValue(false)] + [DisplayName(@"Use URI for connection")] + public bool ConnectWithURI { get; set; } + /// + /// True to declare queue when writing + /// + [DefaultValue(false)] + [DisplayName(@"True to declare queue before writing. False to not declare it")] + public bool Create { get; set; } + /// + /// Durable option when creating queue + /// + [DefaultValue(true)] + [DisplayName(@"Set durable option when creating queue")] + public bool Durable { get; set; } + + } + + + /// + /// Collection of write message parameters + /// + public class WriteBatchInputParams + { + + public WriteBatchInputParams() + { + ExchangeName = String.Empty; + RoutingKey = String.Empty; + } + + /// + /// Data payload + /// + [DisplayName(@"Data")] + [DisplayFormat(DataFormatString = "Expression")] + public byte[] Data { get; set; } + /// + /// Name of the exchange e.g. sampleExchange + /// + [DefaultValue("")] + [DisplayName(@"Exchange name")] + [DisplayFormat(DataFormatString = "Text")] + public string ExchangeName { get; set; } + /// + /// Name of the queue + /// + [DefaultValue("sampleQueue")] + [DisplayName(@"Queue name")] + [DisplayFormat(DataFormatString = "Text")] + public string QueueName { get; set; } + /// + /// Routing key name + /// + [DefaultValue("sampleQueue")] + [DisplayName(@"Routing key")] + [DisplayFormat(DataFormatString = "Text")] + public string RoutingKey { get; set; } + /// + /// RabbitMQ host name + /// + [DisplayName(@"Host name")] + [DisplayFormat(DataFormatString = "Text")] + public string HostName { get; set; } + /// + /// Amount of messages in the buffer under transaction which will be sent over the messaging channel as a chunk. /// [DefaultValue(1)] - [DisplayFormat(DataFormatString = "Text")] + [DisplayFormat(DataFormatString = "Text")] [DisplayName(@"Write message count")] public int WriteMessageCount { get; set; } /// /// Process execution id from the system /// [DefaultValue("#process.executionid")] - [DisplayFormat(DataFormatString = "Expression")] + [DisplayFormat(DataFormatString = "Expression")] [DisplayName(@"Process execution id")] public string ProcessExecutionId { get; set; } /// @@ -146,7 +213,7 @@ public WriteInputParams() [DefaultValue(true)] [DisplayName(@"Set durable option when creating queue")] public bool Durable { get; set; } - + } public class WriteInputParamsString @@ -192,17 +259,79 @@ public WriteInputParamsString() [DisplayFormat(DataFormatString = "Text")] public string HostName { get; set; } /// - /// Amount of messages in the buffer under trasaction which will be sent over the messaging channel as a chunk. + /// Use URI instead of a hostname + /// + [DefaultValue(false)] + [DisplayName(@"Use URI for connection")] + public bool ConnectWithURI { get; set; } + /// + /// True to declare queue when writing + /// + [DefaultValue(false)] + [DisplayName(@"True to declare queue before writing. False to not declare it")] + public bool Create { get; set; } + /// + /// Durable option when creating queue + /// + [DefaultValue(true)] + [DisplayName(@"Set durable option when creating queue")] + public bool Durable { get; set; } + } + + public class WriteBatchInputParamsString + { + public WriteBatchInputParamsString() + { + ExchangeName = String.Empty; + RoutingKey = String.Empty; + } + + /// + /// Data payload in string. Will be internally converted to byte array using UTF8.Convert method + /// + [DisplayName(@"Data")] + [DisplayFormat(DataFormatString = "Text")] + public string Data { get; set; } + + /// + /// Name of the exchange + /// + [DefaultValue("sampleExchange")] + [DisplayName(@"Exchange name")] + [DisplayFormat(DataFormatString = "Text")] + public string ExchangeName { get; set; } + /// + /// Name of the queue + /// + [DefaultValue("sampleQueue")] + [DisplayName(@"Queue name")] + [DisplayFormat(DataFormatString = "Text")] + public string QueueName { get; set; } + /// + /// Routing key name + /// + [DefaultValue("sampleQueue")] + [DisplayName(@"Routing key")] + [DisplayFormat(DataFormatString = "Text")] + public string RoutingKey { get; set; } + /// + /// RabbitMQ host name + /// + [DisplayName(@"Host name")] + [DisplayFormat(DataFormatString = "Text")] + public string HostName { get; set; } + /// + /// Amount of messages in the buffer under transaction which will be sent over the messaging channel as a chunk. /// [DefaultValue(1)] - [DisplayFormat(DataFormatString = "Text")] + [DisplayFormat(DataFormatString = "Text")] [DisplayName(@"Write message count")] public int WriteMessageCount { get; set; } /// /// Process execution id from the system /// [DefaultValue("#process.executionid")] - [DisplayFormat(DataFormatString = "Expression")] + [DisplayFormat(DataFormatString = "Expression")] [DisplayName(@"Process execution id")] public string ProcessExecutionId { get; set; } /// diff --git a/Frends.Community.RabbitMQ/README.md b/Frends.Community.RabbitMQ/README.md index 6c47b05..fb9d346 100644 --- a/Frends.Community.RabbitMQ/README.md +++ b/Frends.Community.RabbitMQ/README.md @@ -30,8 +30,6 @@ Tasks | ExchangeName | string | Name of the exchange | sampleExchange | | RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | -| WriteMessageCount | string | Amount of messages in the buffer which will be sent over messaging queue as a batch. | 20 | -| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | | Create | bool | True to declare queue before writing | False to not declare it| | Durable | bool | Set durable option when creating queue | @@ -44,8 +42,6 @@ Tasks | ExchangeName | string | Name of the exchange | sampleQueue | | RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | -| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | -| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | | Create | bool | True to declare queue before writing | False to not declare it| | Durable | bool | Set durable option when creating queue | @@ -59,7 +55,7 @@ Tasks | QueueName | string | Name of the queue | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | | ReadMessageCount | int | Maximum number of messages to be read from queue. It can exceed number of available messages. | 1 | -| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue,AutoReject,AutoRejectAndRequeue,ManualAck| ReadAckType.AutoAck | +| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue, AutoReject, AutoRejectAndRequeue, ManualAck| ReadAckType.AutoAck | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | ### Output @@ -89,7 +85,7 @@ Tasks | QueueName | string | Name of the queue | sampleQueue | | HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | | ReadMessageCount | int | Maximum number of messages to be read from queue. It can exceed number of available messages. | 1 | -| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue,AutoReject,AutoRejectAndRequeue,ManualAck| ReadAckType.AutoAck | +| AutoAck | enum | Set acknowledgement type. AutoAck,AutoNack, AutoNackAndRequeue, AutoReject,AutoRejectAndRequeue, ManualAck| ReadAckType.AutoAck | | ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | ### OutputString @@ -108,7 +104,36 @@ Tasks | DeliveryTag | ulong | | | +## WriteBatchMessage +### Task Parameters + +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | byte[] | Data to be put in message body| new byte[]{1,2,3}| +| QueueName | string | Name of the queue | sampleQueue | +| ExchangeName | string | Name of the exchange | sampleExchange | +| RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| WriteMessageCount | string | Amount of messages in the buffer which will be sent over messaging queue as a batch. | 20 | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | +| Create | bool | True to declare queue before writing | False to not declare it| +| Durable | bool | Set durable option when creating queue | + + +## WriteBatchMessageString +| Property | Type | Description | Example | +| ---------------------| ---------------------| ------------------------------------ | ----- | +| Data | string | Data to be put in message body| "abc"| +| QueueName | string | Name of the queue | sampleQueue | +| ExchangeName | string | Name of the exchange | sampleQueue | +| RoutingKey | string | Routing key (as in RabbitMQ specification) | sampleQueue | +| HostName | string | Address of the server hosting RabbitMQ | localhost or amqp://user:password@hostname:port/vhost | +| ConnectWithURI | bool | If true, hostname should be an URI | If false, use hostname only | +| ProcessExecutionId | string | Unique id of the process execution. | igbmdajlskdhlfjaeirjwkdjfasdflht | +| Create | bool | True to declare queue before writing | False to not declare it| +| Durable | bool | Set durable option when creating queue | # License diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 8216f99..7ab804f 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -13,17 +13,17 @@ namespace Frends.Community.RabbitMQ public class RabbitMQTask { private static readonly ConnectionFactory Factory = new ConnectionFactory(); - + private static ConcurrentDictionary ConcurrentDictionary = new ConcurrentDictionary(); private static ConcurrentDictionary BatchChannels = new ConcurrentDictionary(); - - private static IConnection CreateConnection(string hostName, bool connectWithURI) + + private static IConnection CreateConnection(string hostName, bool connectWithUri) { lock (Factory) { - IConnection connection = null; + IConnection connection; { - if (connectWithURI) + if (connectWithUri) { Factory.Uri = new Uri(hostName); } @@ -33,27 +33,27 @@ private static IConnection CreateConnection(string hostName, bool connectWithURI } connection = Factory.CreateConnection(); } - - return connection; + + return connection; } } - - private static IConnection CreateBatchConnection(string processExecutionId, string hostName, bool connectWithURI) + + private static IConnection CreateBatchConnection(string processExecutionId, string hostName, bool connectWithUri) { lock (Factory) { - return BatchChannels.GetOrAdd(processExecutionId, - (x) => CreateConnection(hostName, connectWithURI)); + return BatchChannels.GetOrAdd(processExecutionId, + (x) => CreateConnection(hostName, connectWithUri)); } } - - private static IBasicPublishBatch CreateBasicPublishBatch(String processExecutionId, IModel channel) + + private static IBasicPublishBatch CreateBasicPublishBatch(string processExecutionId, IModel channel) { - return ConcurrentDictionary.GetOrAdd(processExecutionId, + return ConcurrentDictionary.GetOrAdd(processExecutionId, (x) => channel.CreateBasicPublishBatch()); } - - private static void DeleteBasicPublishBatch(String processExecutionId) + + private static void DeleteBasicPublishBatch(string processExecutionId) { ConcurrentDictionary.TryRemove(processExecutionId, out var _); } @@ -72,8 +72,8 @@ private static void CloseConnection(IModel channel, IConnection connection) { connection.Close(); } - } - + } + /// /// Closes connection and channel to RabbitMQ /// @@ -89,8 +89,7 @@ private static void CloseBatchConnection(IModel channel, IConnection connection, if (connection != null) { connection.Close(); - BatchChannels.TryRemove(processExecutionId, out var _); - connection = null; + BatchChannels.TryRemove(processExecutionId, out _); } } } @@ -103,7 +102,7 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) { IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); - + try { if (inputParams.Create) @@ -113,40 +112,37 @@ public static bool WriteMessage([PropertyTab] WriteInputParams inputParams) exclusive: false, autoDelete: false, arguments: null); - channel.ConfirmSelect(); + channel.ConfirmSelect(); } IBasicProperties basicProperties = null; - if (inputParams.Durable == true) + if (inputParams.Durable) { basicProperties = channel.CreateBasicProperties(); basicProperties.Persistent = true; } - - if (inputParams.WriteMessageCount <= 1) - { - channel.BasicPublish(exchange: - inputParams.ExchangeName, - routingKey: inputParams.RoutingKey, - basicProperties: basicProperties, - body: inputParams.Data); - return true; - } - return false; + + channel.BasicPublish(exchange: + inputParams.ExchangeName, + routingKey: inputParams.RoutingKey, + basicProperties: basicProperties, + body: inputParams.Data); + return true; + } finally { - CloseConnection(channel, connection); + CloseConnection(channel, connection); } } - + /// /// Writes messages into a queue with batch publish. All messages are under transaction. If one the message failes all messages will be rolled back. /// /// - public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) + public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputParams) { IConnection connection = CreateBatchConnection(inputParams.ProcessExecutionId, inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); @@ -164,12 +160,12 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) IBasicProperties basicProperties = null; - if (inputParams.Durable == true) + if (inputParams.Durable) { basicProperties = channel.CreateBasicProperties(); basicProperties.Persistent = true; } - + // Add message into a memory based on producer write capability. if (channel.MessageCount(inputParams.QueueName) <= inputParams.WriteMessageCount) { @@ -178,7 +174,7 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) routingKey: inputParams.RoutingKey, mandatory: true, properties: basicProperties, - body: inputParams.Data); + body: new ReadOnlyMemory(inputParams.Data)); return false; } @@ -189,8 +185,8 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); channel.TxCommit(); - /** - * rollback only when exception is thrown + /* + rollback only when exception is thrown if (channel.MessageCount(inputParams.QueueName) > 0) { channel.TxRollback(); @@ -200,7 +196,7 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) DeleteBasicPublishBatch(inputParams.ProcessExecutionId); return true; } - catch (Exception exception) + catch (Exception) { channel.TxRollback(); return false; @@ -209,11 +205,11 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) else { return false; - } + } } finally { - CloseBatchConnection(channel, connection, inputParams.ProcessExecutionId); + CloseBatchConnection(channel, connection, inputParams.ProcessExecutionId); } } @@ -222,7 +218,7 @@ public static bool WriteBatchMessage([PropertyTab] WriteInputParams inputParams) /// /// /// - public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputParams) + public static bool WriteMessageString([PropertyTab] WriteInputParamsString inputParams) { WriteInputParams wip = new WriteInputParams { @@ -230,8 +226,6 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP Create = inputParams.Create, Data = Encoding.UTF8.GetBytes(inputParams.Data), Durable = inputParams.Durable, - WriteMessageCount = inputParams.WriteMessageCount, - ProcessExecutionId = inputParams.ProcessExecutionId, HostName = inputParams.HostName, ExchangeName = inputParams.ExchangeName, QueueName = inputParams.QueueName, @@ -246,9 +240,9 @@ public static bool WriteMessageString([PropertyTab]WriteInputParamsString inputP /// /// /// - public static bool WriteTextMessageBatch([PropertyTab]WriteInputParamsString inputParams) + public static bool WriteTextMessageBatch([PropertyTab] WriteBatchInputParamsString inputParams) { - WriteInputParams wip = new WriteInputParams + WriteBatchInputParams wip = new WriteBatchInputParams { ConnectWithURI = inputParams.ConnectWithURI, Create = inputParams.Create, @@ -270,14 +264,14 @@ public static bool WriteTextMessageBatch([PropertyTab]WriteInputParamsString inp /// /// /// JSON structure with message contents - public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) + public static Output ReadMessage([PropertyTab] ReadInputParams inputParams) { IConnection connection = CreateConnection(inputParams.HostName, inputParams.ConnectWithURI); IModel channel = connection.CreateModel(); try { Output output = new Output(); - + while (inputParams.ReadMessageCount-- > 0) { var rcvMessage = channel.BasicGet(queue: inputParams.QueueName, @@ -286,7 +280,8 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) { output.Messages.Add(new Message { - Data = Convert.ToBase64String(rcvMessage.Body.ToArray()), MessagesCount = rcvMessage.MessageCount, + Data = Convert.ToBase64String(rcvMessage.Body.ToArray()), + MessagesCount = rcvMessage.MessageCount, DeliveryTag = rcvMessage.DeliveryTag }); } @@ -327,12 +322,12 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) AcknowledgeMessage(channel, ackType, message.DeliveryTag); } } - + return output; } finally { - CloseConnection(channel, connection); + CloseConnection(channel, connection); } } @@ -341,7 +336,7 @@ public static Output ReadMessage([PropertyTab]ReadInputParams inputParams) /// /// /// JSON structure with message contents - public static OutputString ReadMessageString([PropertyTab]ReadInputParams inputParams) + public static OutputString ReadMessageString([PropertyTab] ReadInputParams inputParams) { var messages = ReadMessage(inputParams); OutputString outString = new OutputString @@ -361,11 +356,9 @@ public static OutputString ReadMessageString([PropertyTab]ReadInputParams inputP /// /// Acknowledges received message. Throws exception on error. /// - /// - /// - public static void AcknowledgeMessage(IModel _channel, ManualAckType ackType, ulong deliveryTag) + public static void AcknowledgeMessage(IModel channel, ManualAckType ackType, ulong deliveryTag) { - if (_channel == null) + if (channel == null) { // do not try to re-connect, because messages already nacked automatically throw new Exception("No connection to RabbitMQ"); @@ -374,24 +367,28 @@ public static void AcknowledgeMessage(IModel _channel, ManualAckType ackType, ul switch (ackType) { case ManualAckType.Ack: - _channel.BasicAck(deliveryTag, multiple: false); + channel.BasicAck(deliveryTag, multiple: false); break; case ManualAckType.Nack: - _channel.BasicNack(deliveryTag, multiple: false, requeue: false); + channel.BasicNack(deliveryTag, multiple: false, requeue: false); break; case ManualAckType.NackAndRequeue: - _channel.BasicNack(deliveryTag, multiple: false, requeue: true); + channel.BasicNack(deliveryTag, multiple: false, requeue: true); break; case ManualAckType.Reject: - _channel.BasicReject(deliveryTag, requeue: false); + channel.BasicReject(deliveryTag, requeue: false); break; case ManualAckType.RejectAndRequeue: - _channel.BasicReject(deliveryTag, requeue: true); + channel.BasicReject(deliveryTag, requeue: true); break; + default: + throw new Exception("Wrong acknowledge type."); + + } } } From 322c8c41bbf2b427ce7f0123d4ed2ca92683913c Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Fri, 11 Dec 2020 09:11:48 +0200 Subject: [PATCH 31/35] Testing batch writing unit tests --- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 54 +++++++++++++++++++ .../packages.config | 9 ---- Frends.Community.RabbitMQ/RabbitMQTask.cs | 1 + Frends.Community.RabbitMQ/packages.config | 6 --- 4 files changed, 55 insertions(+), 15 deletions(-) delete mode 100644 Frends.Community.RabbitMQ.Tests/packages.config delete mode 100644 Frends.Community.RabbitMQ/packages.config diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index 42e7e0d..533e257 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -26,6 +26,10 @@ public class UnitTests private WriteInputParams _inputParameters = new WriteInputParams(); private WriteInputParamsString _inputParametersString = new WriteInputParamsString(); + + private WriteBatchInputParams _inputBatchParameters = new WriteBatchInputParams(); + private WriteBatchInputParamsString _inputBatchParametersString = new WriteBatchInputParamsString(); + private ReadInputParams _outputReadParams; @@ -103,6 +107,32 @@ public void CreateExchangeAndQueue() ReadMessageCount = 1, ConnectWithURI = false }; + + _inputBatchParameters = new WriteBatchInputParams + { + Data = new byte[] { 0, 1, 2 }, + HostName = TestHost, + RoutingKey = "queue", + QueueName = "queue", + ProcessExecutionId = Guid.NewGuid().ToString(), + ConnectWithURI = false, + Create = false, + Durable = false + }; + + + + _inputBatchParametersString = new WriteBatchInputParamsString + { + Data = "test message", + HostName = TestHost, + RoutingKey = "queue", + QueueName = "queue", + ProcessExecutionId = Guid.NewGuid().ToString(), + ConnectWithURI = false, + Create = false, + Durable = false + }; } [Test] @@ -284,5 +314,29 @@ public void TestChangingHostName() Assert.IsTrue(true); } + + [Test] + public void TestReadWithAck10WithUriWithBatchWrite() + { + _inputBatchParameters.HostName = TestUri; + _inputBatchParameters.ConnectWithURI = true; + _inputBatchParameters.WriteMessageCount = 1; + + + _outputReadParams.ConnectWithURI = true; + _outputReadParams.HostName = TestUri; + _outputReadParams.ReadMessageCount = 10; + + for (int i = 0; i < 10; i++) + { + _inputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + + RabbitMQTask.WriteBatchMessage(_inputBatchParameters); + } + + var retVal = RabbitMQTask.ReadMessage(_outputReadParams); + + Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); + } } } diff --git a/Frends.Community.RabbitMQ.Tests/packages.config b/Frends.Community.RabbitMQ.Tests/packages.config deleted file mode 100644 index dd40b67..0000000 --- a/Frends.Community.RabbitMQ.Tests/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 7ab804f..ac502f6 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -213,6 +213,7 @@ rollback only when exception is thrown } } + /// /// Writes message to queue. Message is a string and there is internal conversion from string to byte[] using UTF8 encoding /// diff --git a/Frends.Community.RabbitMQ/packages.config b/Frends.Community.RabbitMQ/packages.config deleted file mode 100644 index 157f190..0000000 --- a/Frends.Community.RabbitMQ/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 85e0631fddb1253350e4a208c900184340af4cbe Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Fri, 11 Dec 2020 14:54:38 +0200 Subject: [PATCH 32/35] More testing with batch write. --- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 3 ++- Frends.Community.RabbitMQ/RabbitMQTask.cs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index 533e257..ea6e883 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -320,7 +320,7 @@ public void TestReadWithAck10WithUriWithBatchWrite() { _inputBatchParameters.HostName = TestUri; _inputBatchParameters.ConnectWithURI = true; - _inputBatchParameters.WriteMessageCount = 1; + _inputBatchParameters.WriteMessageCount = 2; _outputReadParams.ConnectWithURI = true; @@ -330,6 +330,7 @@ public void TestReadWithAck10WithUriWithBatchWrite() for (int i = 0; i < 10; i++) { _inputParameters.Data = new byte[] { 0, (byte)(i * i), (byte)i }; + _inputBatchParameters.ProcessExecutionId = Guid.NewGuid().ToString(); RabbitMQTask.WriteBatchMessage(_inputBatchParameters); } diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index ac502f6..275aa5a 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -175,11 +175,12 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa mandatory: true, properties: basicProperties, body: new ReadOnlyMemory(inputParams.Data)); - return false; + // return false; } + var a = channel.MessageCount(inputParams.QueueName); // Commit under transaction when all of the messages have been received for the producer. - if (channel.MessageCount(inputParams.QueueName) == inputParams.WriteMessageCount) + if (a == inputParams.WriteMessageCount) { try { From 66263f9a360c11c8e0455b321d4b5b8404a03043 Mon Sep 17 00:00:00 2001 From: OssiGalkin Date: Thu, 1 Apr 2021 13:53:06 +0300 Subject: [PATCH 33/35] Removed transactions --- Frends.Community.RabbitMQ/RabbitMQTask.cs | 49 +++++++++++++---------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 275aa5a..0480a5a 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -166,8 +166,12 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa basicProperties.Persistent = true; } + var a = channel.MessageCount(inputParams.QueueName); + + var b = ConcurrentDictionary; + // Add message into a memory based on producer write capability. - if (channel.MessageCount(inputParams.QueueName) <= inputParams.WriteMessageCount) + if (a < inputParams.WriteMessageCount) { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( exchange: inputParams.ExchangeName, @@ -175,37 +179,38 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa mandatory: true, properties: basicProperties, body: new ReadOnlyMemory(inputParams.Data)); - // return false; + + var c = inputParams.WriteMessageCount; + + if (ConcurrentDictionary.Count < 9) + return false; } - var a = channel.MessageCount(inputParams.QueueName); - // Commit under transaction when all of the messages have been received for the producer. - if (a == inputParams.WriteMessageCount) - { - try + + + try { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); - channel.TxCommit(); - /* - rollback only when exception is thrown - if (channel.MessageCount(inputParams.QueueName) > 0) - { - channel.TxRollback(); - return false; - } - */ - DeleteBasicPublishBatch(inputParams.ProcessExecutionId); - return true; - } - catch (Exception) + //channel.TxCommit(); + /* + rollback only when exception is thrown + if (channel.MessageCount(inputParams.QueueName) > 0) { channel.TxRollback(); return false; } - } - else + */ + //DeleteBasicPublishBatch(inputParams.ProcessExecutionId); + + var d = channel.MessageCount(inputParams.QueueName); + + return true; + } + catch (Exception) { + channel.TxRollback(); return false; + } } finally From a5ca7487871ffc27e536ca4ac2897f6925d06bfb Mon Sep 17 00:00:00 2001 From: ileinone Date: Thu, 1 Apr 2021 14:36:33 +0300 Subject: [PATCH 34/35] Transaction support not supported by driver. Using acknoledgement and queue purging. --- Frends.Community.RabbitMQ/Definitions.cs | 13 ++++++- Frends.Community.RabbitMQ/RabbitMQTask.cs | 45 ++++++++++------------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Frends.Community.RabbitMQ/Definitions.cs b/Frends.Community.RabbitMQ/Definitions.cs index ce9874a..defb941 100644 --- a/Frends.Community.RabbitMQ/Definitions.cs +++ b/Frends.Community.RabbitMQ/Definitions.cs @@ -213,7 +213,15 @@ public WriteBatchInputParams() [DefaultValue(true)] [DisplayName(@"Set durable option when creating queue")] public bool Durable { get; set; } - + + /// + /// Amount of seconds waiting for confirmation messages. + /// + [DefaultValue(1)] + [DisplayFormat(DataFormatString = "Text")] + [DisplayName(@"Wait for acknowledgement in seconds")] + public int WaitForAcknowledgement { get; set; } + } public class WriteInputParamsString @@ -321,12 +329,13 @@ public WriteBatchInputParamsString() [DisplayFormat(DataFormatString = "Text")] public string HostName { get; set; } /// - /// Amount of messages in the buffer under transaction which will be sent over the messaging channel as a chunk. + /// Amount of messages in the buffer under acknoledgement which will be sent over the messaging channel as a chunk. /// [DefaultValue(1)] [DisplayFormat(DataFormatString = "Text")] [DisplayName(@"Write message count")] public int WriteMessageCount { get; set; } + /// /// Process execution id from the system /// diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index 0480a5a..a0ccd67 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -165,13 +165,9 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa basicProperties = channel.CreateBasicProperties(); basicProperties.Persistent = true; } - - var a = channel.MessageCount(inputParams.QueueName); - - var b = ConcurrentDictionary; - + // Add message into a memory based on producer write capability. - if (a < inputParams.WriteMessageCount) + if (channel.MessageCount(inputParams.QueueName) < inputParams.WriteMessageCount) { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Add( exchange: inputParams.ExchangeName, @@ -182,33 +178,32 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa var c = inputParams.WriteMessageCount; - if (ConcurrentDictionary.Count < 9) + if (ConcurrentDictionary.Count < inputParams.WriteMessageCount) return false; } - - - + try { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); - //channel.TxCommit(); - /* - rollback only when exception is thrown - if (channel.MessageCount(inputParams.QueueName) > 0) - { - channel.TxRollback(); - return false; - } - */ - //DeleteBasicPublishBatch(inputParams.ProcessExecutionId); - - var d = channel.MessageCount(inputParams.QueueName); - - return true; + channel.WaitForConfirmsOrDie(new TimeSpan(0, 0, inputParams.WaitForAcknowledgement )); + //channel.TxCommit(); + /* + rollback only when exception is thrown + if (channel.MessageCount(inputParams.QueueName) > 0) + { + channel.TxRollback(); + return false; + } + */ + //DeleteBasicPublishBatch(inputParams.ProcessExecutionId); + + var d = channel.MessageCount(inputParams.QueueName); + return true; } catch (Exception) { - channel.TxRollback(); + channel.QueuePurge(inputParams.QueueName); + //channel.TxRollback(); return false; } From 9efcb6ad4cb1bf65547912cea4ab2ca72ee54287 Mon Sep 17 00:00:00 2001 From: ileinone Date: Tue, 18 May 2021 15:16:04 +0300 Subject: [PATCH 35/35] Fix for batch handling. --- Frends.Community.RabbitMQ.Tests/UnitTests.cs | 9 +++++---- Frends.Community.RabbitMQ/RabbitMQTask.cs | 19 ++++--------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/Frends.Community.RabbitMQ.Tests/UnitTests.cs b/Frends.Community.RabbitMQ.Tests/UnitTests.cs index ea6e883..6a07770 100644 --- a/Frends.Community.RabbitMQ.Tests/UnitTests.cs +++ b/Frends.Community.RabbitMQ.Tests/UnitTests.cs @@ -20,8 +20,8 @@ namespace Frends.Community.RabbitMQ.Tests public class UnitTests { - //public const string TestURI = "amqp://user:password@hostname:port/vhost"; - public static string TestUri = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); + public const string TestUri = "amqp://agent:agent123@localhost:5772"; + //public static string TestUri = Environment.GetEnvironmentVariable("HIQ_RABBITMQ_CONNECTIONSTRING"); public static string TestHost = "localhost"; private WriteInputParams _inputParameters = new WriteInputParams(); @@ -320,7 +320,8 @@ public void TestReadWithAck10WithUriWithBatchWrite() { _inputBatchParameters.HostName = TestUri; _inputBatchParameters.ConnectWithURI = true; - _inputBatchParameters.WriteMessageCount = 2; + _inputBatchParameters.WriteMessageCount = 10; + _inputBatchParameters.WaitForAcknowledgement = 5; _outputReadParams.ConnectWithURI = true; @@ -337,7 +338,7 @@ public void TestReadWithAck10WithUriWithBatchWrite() var retVal = RabbitMQTask.ReadMessage(_outputReadParams); - Assert.IsTrue(retVal != null && retVal.Messages.Count() == 10); + Assert.IsTrue(retVal != null && retVal.Messages.Count() < 10); } } } diff --git a/Frends.Community.RabbitMQ/RabbitMQTask.cs b/Frends.Community.RabbitMQ/RabbitMQTask.cs index a0ccd67..ebd2059 100644 --- a/Frends.Community.RabbitMQ/RabbitMQTask.cs +++ b/Frends.Community.RabbitMQ/RabbitMQTask.cs @@ -185,25 +185,14 @@ public static bool WriteBatchMessage([PropertyTab] WriteBatchInputParams inputPa try { CreateBasicPublishBatch(inputParams.ProcessExecutionId, channel).Publish(); + channel.ConfirmSelect(); channel.WaitForConfirmsOrDie(new TimeSpan(0, 0, inputParams.WaitForAcknowledgement )); - //channel.TxCommit(); - /* - rollback only when exception is thrown - if (channel.MessageCount(inputParams.QueueName) > 0) - { - channel.TxRollback(); - return false; - } - */ - //DeleteBasicPublishBatch(inputParams.ProcessExecutionId); - - var d = channel.MessageCount(inputParams.QueueName); - return true; + var messageCount = channel.MessageCount(inputParams.QueueName); + return messageCount == inputParams.WriteMessageCount; } catch (Exception) { channel.QueuePurge(inputParams.QueueName); - //channel.TxRollback(); return false; } @@ -287,7 +276,7 @@ public static Output ReadMessage([PropertyTab] ReadInputParams inputParams) DeliveryTag = rcvMessage.DeliveryTag }); } - //break the loop if no more messagages are present + //break the loop if no more messages are present else { break;