Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
RabbitMQ生产者C#.NET核心5.0内存泄漏_C#_.net_Memory Leaks_Rabbitmq - Fatal编程技术网

RabbitMQ生产者C#.NET核心5.0内存泄漏

RabbitMQ生产者C#.NET核心5.0内存泄漏,c#,.net,memory-leaks,rabbitmq,C#,.net,Memory Leaks,Rabbitmq,我想知道是否有人能在以下情况下提供帮助: 使用C#编写的RabbitMQ发布服务器并使用.Net core 5.0,我无法解决内存泄漏问题 这是csproj文件: <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFr

我想知道是否有人能在以下情况下提供帮助:

使用C#编写的RabbitMQ发布服务器并使用.Net core 5.0,我无法解决内存泄漏问题

这是csproj文件:

<Project Sdk="Microsoft.NET.Sdk">   
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>
  ...
</Project>  
这导致了程序的最终崩溃:

我采取了哪些措施来防止内存泄漏

  • 这些类启用了IDisposable接口
  • 在收到每条消息后强制垃圾收集:
  • 这有点帮助,现在我的记忆问题增加了一段时间后

  • 我使用VisualStudio的Reformer()插件来更好地理解内存问题的堆栈跟踪,但它没有多大帮助
  • 我认为问题出在哪里

    RabbitMQ Producer应用程序每秒获取许多消息,然后解析这些消息,将其拆分为多个JSON消息,并使用相同的通道发送到RMQ。可能发生以下情况:

    • 我在一个RMQ频道上发布,不知何故我应该使用多个频道(一个连接但多个频道)
    • 我收到的消息比使用RabbitMQ.Client.net库通过RMQ解析和发送的消息还要多
    • 我在内存中保留了一些未被释放的对象(可能是消息)的引用
    以前有人有过这个问题吗?因为我在任何地方都找不到有关“SingleProducerSingleConsumerQueue+段内存不足”问题的任何信息

    有人知道如何更深入地分析这个问题吗

    非常感谢


    编辑1 我想需要更多的信息来解决这个内存问题

    我有几个消费者使用来自RabbitMQ的数据(比如NodeJS和python应用程序)。因此,我需要以通用的方式设计RabbitMQ生产者,因为每个消费者需要不同的数据。而且,每次我有一个新的消费者应用程序时,我都无法修改和重新启动RabbitMQ Producer。所以我需要以一种通用的方式发布我的消息

    例如,每个使用者都有自己的专用队列和专用绑定。假设我的consumer1具有队列cons1和绑定:

    • marketName.productName.*.1(产品名称将对应数天)
    这种绑定是动态的,目前它对应于星期一(4月4日),但明天它将对应于星期二(4月5日)

    因此,我需要使用

    private static read-only Dictionary<string, List<string>> sequenceItemsHashed = new Dictionary<string, List<string>>();
    private static readonly Dictionary<string, string> sequencesFromInstruments = new Dictionary<string, string>();
    
    还有我的新RabbitMQ类:

    public class RMQ : IDisposable {
        private IConnection _connection;
        public IModel Channel { get; private set; }        
        private readonly ConnectionFactory _connectionFactory;
        private readonly string _exchangeName;
    
        public RMQ (RabbitOptions _rabbitOptions){
            try{
                // _connectionFactory initialization
                _connectionFactory = new ConnectionFactory()
                {
                    HostName = _rabbitOptions.HostName,
                    UserName = _rabbitOptions.UserName,
                    Password = _rabbitOptions.Password,
                    VirtualHost = _rabbitOptions.VHost,
                };
                this._exchangeName = _rabbitOptions.ExchangeName;
    
                if (!String.IsNullOrEmpty(_rabbitOptions.CertPath)){
                    _connectionFactory.RequestedConnectionTimeout = TimeSpan.FromMilliseconds(5000);
                    _connectionFactory.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch | SslPolicyErrors.RemoteCertificateChainErrors;
                    _connectionFactory.Ssl.CertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
                    _connectionFactory.Ssl.ServerName = _rabbitOptions.HostName;
                    _connectionFactory.Ssl.CertPath = _rabbitOptions.CertPath;
                    _connectionFactory.Ssl.CertPassphrase = _rabbitOptions.CertPass;
                    _connectionFactory.Ssl.Version = SslProtocols.Tls12;
                    _connectionFactory.Ssl.Enabled = true;
                }
    
                _connectionFactory.RequestedHeartbeat = TimeSpan.FromSeconds(1);
                _connectionFactory.AutomaticRecoveryEnabled = true;        // enable automatic connection recovery
                //_connectionFactory.RequestedChannelMax = 10;
    
                if (_connection == null || _connection.IsOpen == false){
                    _connection = _connectionFactory.CreateConnection();
                    _connection.ConnectionShutdown += Connection_ConnectionShutdown;
                }
                if (Channel == null || Channel.IsOpen == false){
                    Channel = _connection.CreateModel();
                }
                Utils.log.Info("ConnectToRabbitMQ () Connecting to RabbitMQ. rabbitMQenvironment = ");
            }
            catch (Exception ex){
                Utils.log.Error("Connection to RabbitMQ failed ! HostName = " + _rabbitOptions.HostName + " VirtualHost = " + _rabbitOptions.VHost);
                Utils.printException("ConnectToRMQ ()", ex);
            }
        }        
    
        private void Connection_ConnectionShutdown(object sender, ShutdownEventArgs e){
            Utils.log.Info ("Connection broke!");
            try{
                if (ReconnectToRMQ()){
                    Utils.log.Info("Connected!");
                }
            }
            catch (Exception ex){
                Utils.log.Info("Connect failed!" + ex.Message);
            }
        }
    
        private bool ReconnectToRMQ(){
            if (_connection == null || _connection.IsOpen == false){
                _connection = _connectionFactory.CreateConnection();
                _connection.ConnectionShutdown += Connection_ConnectionShutdown;                
            }
    
            if (Channel == null || Channel.IsOpen == false){
                Channel = _connection.CreateModel();
                return true;
            }
            return false;
        }
    
        private bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
            return true;
        }
    
        public void DisconnectFromRMQ () {
            Channel.Close ();
            _connection.Close ();
        }     
    
        public void Dispose(){
            try{
                Channel?.Close();
                Channel?.Dispose();
                Channel = null;
    
                _connection?.Close();
                _connection?.Dispose();
                _connection = null;
            }
            catch (Exception e){
                Utils.log.Error("Cannot dispose RabbitMQ channel or connection" + e.Message);
            }
        }
    
        public void PublishMessages (byte [] message, string routingKey) {            
            if (this._connection == null || ! _connection.IsOpen) {
                Utils.log.Error ("PublishMessages(), Connect failed! this.conn == null || !conn.IsOpen ");
                ReconnectToRMQ();
            } else { 
                var properties = Channel.CreateBasicProperties();
                properties.Persistent = true;
    
                Channel.BasicPublish (_exchangeName, routingKey, properties, message);
                //serviceInstance1.Publish(message, _rabbitOptions.ExchangeName, "", routingKey);
            }
        }
    }
    

    现在有趣的是,如果我只将一个小字符串(如“test”)发布到RabbitMQ的预定义队列中,我可以每秒发布超过1780条消息。

    首先,似乎您正在阻塞事件处理线程。 因此,我要做的是将事件处理与实际处理分离:

    (未经测试!只是一个大纲!)

    已删除故障代码

    然后在
    serviceInstance1
    中,我会让
    Publish
    将订单排队到一个BlockingCollection中,其中有一个专用线程正在等待。该线程将执行实际发送。因此,无论您选择在
    处理器中执行什么操作,您都会将订单整理到该线程,所有这些订单都将被解耦并按顺序进行

    您可能需要根据自己的需求设置BlockOptions

    请记住,这只是一个粗略的轮廓,不是一个完整的解决方案。您可能还希望从那里开始,最小化字符串操作等

    编辑 从昨天开始,我有了更多的想法,没有什么特别的顺序:

    • 放弃第一个过滤器以在以后过滤掉空的作业对象集是否有益
    • 也许值得尝试使用
    • 从xml到json有没有更有效的方法?(我在想“XSLT”,但真的不确定)
    • 我建议使用MemoryAnalyzer来记录/证明您的更改具有积极的影响
    • 别忘了研究如何调整管道的行为
    供参考:
    针对问题中的编辑3: 这真的不是个好主意

    首先,我会在处理发送的服务类中这样做(
    serviceInstance1
    -不知道类型)。然后,在将TPL与Thread.Sleep混合时,您正在使用spin wait进行紧密循环。那是两个诺诺。它还完全扰乱了阻塞队列的意图。也就是说:线程阻塞,直到该队列上有可用的项

    也许现在最好完全放弃这个部分,让管道中的最后一个块执行
    serviceInstance1.Publish
    。这可能是过早的优化

    编辑2 所以,昨天我做了一些实验,发现:

    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    using Newtonsoft.Json;
    using System.Linq;
    
    namespace DataFlowExperiment.PipelinesLib
    {
    
        public class PipelineOne
        {
            private readonly IPipelineOneSteps steps;
    
            private readonly TransformBlock<string, XDocument> startBlock; // XML deserialize to Model
            private readonly TransformManyBlock<XDocument, string> toJsonMessagesBlock; // jsons generieren.
            private readonly ITargetBlock<string> resultCallback;
    
            public PipelineOne(IPipelineOneSteps steps, ITargetBlock<string> resultCallback = null)
            {
                this.steps = steps;
    
                startBlock = new TransformBlock<string, XDocument>(steps.Start);
                toJsonMessagesBlock = new TransformManyBlock<XDocument, string>(steps.ToJson);
    
                this.resultCallback = resultCallback ?? DataflowBlock.NullTarget<string>();
    
                startBlock.LinkTo(toJsonMessagesBlock, new DataflowLinkOptions { PropagateCompletion = true });
                toJsonMessagesBlock.LinkTo(this.resultCallback, new DataflowLinkOptions { PropagateCompletion = true }, x => !string.IsNullOrEmpty(x));
                toJsonMessagesBlock.LinkTo(DataflowBlock.NullTarget<string>(), new DataflowLinkOptions { PropagateCompletion = true });
            }
    
            public void Post(string input)
            {
                startBlock.Post(input);
            }
    
            public Task Close()
            {
                startBlock.Complete();
                return resultCallback.Completion;
            }
        }
    
        public interface IPipelineOneSteps
        {
            public XDocument Start(string input);
            public IEnumerable<string> ToJson(XDocument doc);
        }
    
        public class PipelineOneSteps : IPipelineOneSteps
        {
            private readonly JsonSerializer jsonSerializer;
    
            public PipelineOneSteps()
            {
                jsonSerializer = JsonSerializer.CreateDefault();
            }
    
            public XDocument Start(string input)
            {
                XDocument doc = XDocument.Parse(input);
                return doc;
            }
    
            public IEnumerable<string> ToJson(XDocument doc)
            {
                XNamespace ns = "api-com";
                var orders = doc.Root.Elements(ns + "ORDER");
    
                foreach (var order in orders)
                {
                    yield return JsonConvert.SerializeXNode(order);
                }
            }
        }
    }
    
    方法 N 卑鄙 错误 标准偏差 第0代 第1代 第2代 分配 PipeLineOneBenchmark 1000 25.00μs 0.269μs 0.252μs - - - - PipeLineOneBenchmark 100000 2491.42μs 13.655μs 15.177μs - - - -
    “使用以下命令手动释放内存:”-这不是您实际要做的。您建议运行时执行GC。如果你觉得自己需要这个,那你就有另一个问题了。在这里,似乎是分配和/或引用被保留太久。所以,我要做的是用足够的数据来建立一个基准,以获得真实的测量结果。然后调整所有已识别的瓶颈(一个接一个),并比较基准测试。保持改进,放弃没有任何改进的更改。
    SetUpApi
    最多调用一次吗?如果没有,有多少ti
      <?xml version="1.0" encoding="utf-16"?>
      <APIDATA xmlns="api-com">
      <ORDER ... PersistentOrderID="2791" OrderID="1234" ... Action="Insert" ...>
          ...
      </ORDER>
    
      <?xml version="1.0" encoding="utf-16"?>
      <APIDATA xmlns="api-com">
      <ORDER ... PersistentOrderID="2791" OrderID="1234" ... Action="Remove" ...>
          ...
      </ORDER>
    
    class RabbitManager : IRabbitManager
    {
        private readonly DefaultObjectPool<IModel> _objectPool;
        public RabbitManager(IPooledObjectPolicy<IModel> objectPolicy){
            _objectPool = new DefaultObjectPool<IModel>(objectPolicy, Environment.ProcessorCount * 2);
        }
    
        public void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey) where T : class {
            if (message == null)
                return;
    
            var channel = _objectPool.Get();
            try{
                var sendBytes = Encoding.UTF8.GetBytes(message.ToString());
                var properties = channel.CreateBasicProperties();
                properties.ContentType = "application/json";
                properties.DeliveryMode = 1; // Doesn't persist to disk
                properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
    
                channel.BasicPublish(exchangeName, routeKey, properties, sendBytes);
            }
            catch (Exception ex) {
                throw ex;
            }
            finally {
                _objectPool.Return(channel);
            }
        }
    }
    
    public class RabbitModelPooledObjectPolicy : IPooledObjectPolicy<IModel>
    {
        private readonly RabbitOptions _options;
        private readonly IConnection _connection;
    
        public RabbitModelPooledObjectPolicy(RabbitOptions _options){
            this._options = _options;
            _connection = GetConnection();
        }
    
        private IConnection GetConnection() {
            var factory = new ConnectionFactory() {
                HostName = _options.HostName,
                UserName = _options.UserName,
                Password = _options.Password,
                //Port = _options.Port,
                VirtualHost = _options.VHost,
            };
    
            if (!String.IsNullOrEmpty(_options.CertPath))
            {
                factory.RequestedConnectionTimeout = TimeSpan.FromMilliseconds(5000);
                factory.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch | SslPolicyErrors.RemoteCertificateChainErrors;
                factory.Ssl.CertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
                factory.Ssl.ServerName = _options.HostName;
                factory.Ssl.CertPath = _options.CertPath;
                factory.Ssl.CertPassphrase = _options.CertPass;
                factory.Ssl.Version = SslProtocols.Tls12;
                factory.Ssl.Enabled = true;
            }
    
            factory.RequestedHeartbeat = TimeSpan.FromSeconds(1);
            factory.AutomaticRecoveryEnabled = true;        // enable automatic connection recovery
            factory.RequestedChannelMax = 32;
    
            var _connection = factory.CreateConnection();
            _connection.ConnectionShutdown += Connection_ConnectionShutdown;
    
            return _connection;
        }
    
        private void Connection_ConnectionShutdown(object sender, ShutdownEventArgs e){
            Utils.log.Info("Connection broke!");
        }
    
        private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors){
            return true;
        }
    
        public IModel Create(){
            return _connection.CreateModel();
        }
    
        public bool Return(IModel obj) {
            if (obj.IsOpen) {
                return true;
            }
            else {
                obj?.Dispose();
                return false;
            }
        }
    }
    
    26-04-2021 10:41:48 - OnNewData () RabbitMQ.Client.Exceptions.AlreadyClosedException: Already closed: The AMQP operation was interrupted: AMQP close-reason, initiated by Library, code=0, text='End of stream', classId=0, methodId=0, cause=System.IO.EndOfStreamException: Reached the end of the stream. Possible authentication failure.
       at RabbitMQ.Client.Impl.InboundFrame.ReadFrom(Stream reader, Byte[] frameHeaderBuffer)
       at RabbitMQ.Client.Framing.Impl.Connection.MainLoopIteration()
       at RabbitMQ.Client.Framing.Impl.Connection.MainLoop()
       at RabbitMQ.Client.Framing.Impl.Connection.EnsureIsOpen()
       at RabbitMQ.Client.Framing.Impl.AutorecoveringConnection.CreateModel()
       at RabbitModelPooledObjectPolicy.Create() in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\RabbitMQ\RabbitModelPooledObjectPolicy.cs:line 77
       at Microsoft.Extensions.ObjectPool.DefaultObjectPool`1.Create()
       at Microsoft.Extensions.ObjectPool.DefaultObjectPool`1.Get()
       at RabbitManager.Publish[T](T message, String exchangeName, String exchangeType, String routeKey) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\RabbitMQ\RabbitManager.cs:line 32
       at ConsoleApp1.Service1.SendOrderToRMQ(JObject order) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 411
       at ConsoleApp1.Service1.ParseXMLAnswer(String strOutputXML, String caller) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 372
       at ConsoleApp1.Service1.OnNewData(String strXML) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 348
    26-04-2021 10:41:48 - OnNewData () RabbitMQ.Client.Exceptions.AlreadyClosedException: Already closed: The AMQP operation was interrupted: AMQP close-reason, initiated by Library, code=0, text='End of stream', classId=0, methodId=0, cause=System.IO.EndOfStreamException: Reached the end of the stream. Possible authentication failure.
       at RabbitMQ.Client.Impl.InboundFrame.ReadFrom(Stream reader, Byte[] frameHeaderBuffer)
       at RabbitMQ.Client.Framing.Impl.Connection.MainLoopIteration()
       at RabbitMQ.Client.Framing.Impl.Connection.MainLoop()
       at RabbitMQ.Client.Framing.Impl.Connection.EnsureIsOpen()
       at RabbitMQ.Client.Framing.Impl.AutorecoveringConnection.CreateModel()
       at RabbitModelPooledObjectPolicy.Create() in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\RabbitMQ\RabbitModelPooledObjectPolicy.cs:line 77
       at Microsoft.Extensions.ObjectPool.DefaultObjectPool`1.Create()
       at Microsoft.Extensions.ObjectPool.DefaultObjectPool`1.Get()
       at RabbitManager.Publish[T](T message, String exchangeName, String exchangeType, String routeKey) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\RabbitMQ\RabbitManager.cs:line 32
       at ConsoleApp1.Service1.SendOrderToRMQ(JObject order) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 411
       at ConsoleApp1.Service1.ParseXMLAnswer(String strOutputXML, String caller) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 372
       at ConsoleApp1.Service1.OnNewData(String strXML) in C:\Users\user\Desktop\Projects\ConsoleCoreApp1\Service1.cs:line 348
    
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                {
                    // free managed resources
                    _onTimePerHour.Dispose();
                    _api.OnNewData -= OnNewData;
                }
                // free native resources if there are any.
            }
    
    private void ParseXMLAnswer(string strOutputXML, string caller) {
                ...
                doc = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
    }
    
    private static read-only Dictionary<string, List<string>> sequenceItemsHashed = new Dictionary<string, List<string>>();
    private static readonly Dictionary<string, string> sequencesFromInstruments = new Dictionary<string, string>();
    
    private readonly TransformBlock<string, string> orderFilter;
    private readonly TransformBlock<string, JObject> xmlParser;
    //private readonly TransformBlock<XmlDocument, JObject> xmlToJsonTransformer;
    private readonly TransformManyBlock<JObject, JToken> jsonOrderFactory;
    private readonly ActionBlock<JToken> messageSender;
    
    ConcurrentQueue<JToken> concurrentQueue = new ConcurrentQueue<JToken>();
    
    public Service1 (string [] args) {
        ...
        // setup pipeline blocks
        orderFilter = new TransformBlock<string, string>(FilterIncomingMessages);
        xmlParser = new TransformBlock<string, JObject>(ParseXml);
        jsonOrderFactory = new TransformManyBlock<JObject, JToken>(CreateOrderMessages);
        messageSender = new ActionBlock<JToken>(SendMessage);
    
        // build your pipeline            
        orderFilter.LinkTo(xmlParser, x => !string.IsNullOrEmpty(x));
        orderFilter.LinkTo(DataflowBlock.NullTarget<string>()); // for non-order msgs
    
        xmlParser.LinkTo(jsonOrderFactory);
        jsonOrderFactory.LinkTo(messageSender, new DataflowLinkOptions { PropagateCompletion = true });
    
        Task t2 = Task.Factory.StartNew(() =>
                {
                    while (true) { 
                        if (!concurrentQueue.IsEmpty)
                        {
                            JToken number;
                            while (concurrentQueue.TryDequeue(out number))
                            {
                                _rabbitMQ.PublishMessages(
                                    Encoding.ASCII.GetBytes(number.ToString()),
                                    "test"
                                );
                            }
                        } else
                        {
                            Thread.Sleep(1);
                        }
                    }
                });        
         ...
    }
    
    private string FilterIncomingMessages(string strXml){
        if (strXml.Contains("<ORDER")) return strXml;
        return null;
    }
    
    private JObject ParseXml(string strXml){
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(strXml);
        string jsonText = JsonConvert.SerializeXmlNode(doc);
        var o = JObject.Parse(jsonText);
        return o;
    }
    
    private IEnumerable<JToken> CreateOrderMessages(JObject o){
        List<JToken> myList = new List<JToken>();
                if (o.ContainsKey("GV8APIDATA")){
                    if (o["GV8APIDATA"]["ORDER"].Type is JTokenType.Object){
                        JToken order = o["GV8APIDATA"]["ORDER"];
                        myList.Add(order);
                    }
                    else if (o["GV8APIDATA"]["ORDER"].Type is JTokenType.Array){
                        JToken orders = o["GV8APIDATA"]["ORDER"];
                        foreach (var order in orders.Children()){
                            myList.Add(order);
                        }
                    }
                }
                return myList.ToArray ();
            }
    
    private void SendMessage(JToken order){
        concurrentQueue.Enqueue(order);
    }
    
    public Service1 (string [] args) {
                ...             
                // setup pipeline blocks
                orderFilter = new TransformBlock<string, string>(FilterIncomingMessages);
                xmlParser = new TransformBlock<string, OrdersResponse>(ParseXml);
                jsonOrderFactory = new TransformManyBlock<OrdersResponse, Order>(CreateOrderMessages);
                messageSender = new ActionBlock<Order>(SendMessage);
    
                // build your pipeline            
                orderFilter.LinkTo(xmlParser, x => !string.IsNullOrEmpty(x));
                orderFilter.LinkTo(DataflowBlock.NullTarget<string>()); // for non-order msgs
                xmlParser.LinkTo(jsonOrderFactory);
                jsonOrderFactory.LinkTo(messageSender, new DataflowLinkOptions { PropagateCompletion = true });
    
                RunAsConsole(args);
            }
    
            private readonly TransformBlock<string, string> orderFilter;
            private readonly TransformBlock<string, OrdersResponse> xmlParser;
            private readonly TransformManyBlock<OrdersResponse, Order> jsonOrderFactory;
            private readonly ActionBlock<Order> messageSender;
    
            private void OnNewData(string strXML){
                orderFilter.Post(strXML); 
            }        
    
            private string FilterIncomingMessages(string strXml){
                if (strXml.Contains("<ORDER")) return strXml;
                return null;
            }
    
            private OrdersResponse ParseXml(string strXml) {
                var rootDataObj = DeserializeOrdersFromXML(strXml);
                return rootDataObj;
            }
    
            private OrdersResponse DeserializeOrdersFromXML(string strOutputXML){
                var xsExpirations = new XmlSerializer(typeof(OrdersResponse));
                OrdersResponse rootDataObj = null;
                using (TextReader reader = new StringReader(strOutputXML)) {
                    rootDataObj = (OrdersResponse)xsExpirations.Deserialize(reader);
                    reader.Close();
                }
                return rootDataObj;
            }
    
            private IEnumerable<Order> CreateOrderMessages(OrdersResponse o){
                return o.orders;
            }
    
            private void SendMessage(Order order) {
                _rabbitMQ.PublishMessages(
                        Encoding.ASCII.GetBytes(order.ToString()),
                        "test"
                    );
            }
    
        [Serializable()]
        [XmlRoot (ElementName = "ORDER")]
        public class Order : IDisposable {
    
            public void Dispose()
            {
                EngineID = null;
                PersistentOrderID = null;
                ...
                InstrumentSpecifier.Dispose();
                InstrumentSpecifier = null;
                GC.SuppressFinalize(this);
            }
    
            [XmlAttribute (AttributeName = "EngineID")]
            public string EngineID { get; set; }
            [XmlAttribute (AttributeName = "PersistentOrderID")]
            public string PersistentOrderID { get; set; }
            ... 
            [XmlElement(ElementName = "INSTSPECIFIER")]
            public InstrumentSpecifier InstrumentSpecifier { get; set; }
        }
    
    public class RMQ : IDisposable {
        private IConnection _connection;
        public IModel Channel { get; private set; }        
        private readonly ConnectionFactory _connectionFactory;
        private readonly string _exchangeName;
    
        public RMQ (RabbitOptions _rabbitOptions){
            try{
                // _connectionFactory initialization
                _connectionFactory = new ConnectionFactory()
                {
                    HostName = _rabbitOptions.HostName,
                    UserName = _rabbitOptions.UserName,
                    Password = _rabbitOptions.Password,
                    VirtualHost = _rabbitOptions.VHost,
                };
                this._exchangeName = _rabbitOptions.ExchangeName;
    
                if (!String.IsNullOrEmpty(_rabbitOptions.CertPath)){
                    _connectionFactory.RequestedConnectionTimeout = TimeSpan.FromMilliseconds(5000);
                    _connectionFactory.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch | SslPolicyErrors.RemoteCertificateChainErrors;
                    _connectionFactory.Ssl.CertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
                    _connectionFactory.Ssl.ServerName = _rabbitOptions.HostName;
                    _connectionFactory.Ssl.CertPath = _rabbitOptions.CertPath;
                    _connectionFactory.Ssl.CertPassphrase = _rabbitOptions.CertPass;
                    _connectionFactory.Ssl.Version = SslProtocols.Tls12;
                    _connectionFactory.Ssl.Enabled = true;
                }
    
                _connectionFactory.RequestedHeartbeat = TimeSpan.FromSeconds(1);
                _connectionFactory.AutomaticRecoveryEnabled = true;        // enable automatic connection recovery
                //_connectionFactory.RequestedChannelMax = 10;
    
                if (_connection == null || _connection.IsOpen == false){
                    _connection = _connectionFactory.CreateConnection();
                    _connection.ConnectionShutdown += Connection_ConnectionShutdown;
                }
                if (Channel == null || Channel.IsOpen == false){
                    Channel = _connection.CreateModel();
                }
                Utils.log.Info("ConnectToRabbitMQ () Connecting to RabbitMQ. rabbitMQenvironment = ");
            }
            catch (Exception ex){
                Utils.log.Error("Connection to RabbitMQ failed ! HostName = " + _rabbitOptions.HostName + " VirtualHost = " + _rabbitOptions.VHost);
                Utils.printException("ConnectToRMQ ()", ex);
            }
        }        
    
        private void Connection_ConnectionShutdown(object sender, ShutdownEventArgs e){
            Utils.log.Info ("Connection broke!");
            try{
                if (ReconnectToRMQ()){
                    Utils.log.Info("Connected!");
                }
            }
            catch (Exception ex){
                Utils.log.Info("Connect failed!" + ex.Message);
            }
        }
    
        private bool ReconnectToRMQ(){
            if (_connection == null || _connection.IsOpen == false){
                _connection = _connectionFactory.CreateConnection();
                _connection.ConnectionShutdown += Connection_ConnectionShutdown;                
            }
    
            if (Channel == null || Channel.IsOpen == false){
                Channel = _connection.CreateModel();
                return true;
            }
            return false;
        }
    
        private bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
            return true;
        }
    
        public void DisconnectFromRMQ () {
            Channel.Close ();
            _connection.Close ();
        }     
    
        public void Dispose(){
            try{
                Channel?.Close();
                Channel?.Dispose();
                Channel = null;
    
                _connection?.Close();
                _connection?.Dispose();
                _connection = null;
            }
            catch (Exception e){
                Utils.log.Error("Cannot dispose RabbitMQ channel or connection" + e.Message);
            }
        }
    
        public void PublishMessages (byte [] message, string routingKey) {            
            if (this._connection == null || ! _connection.IsOpen) {
                Utils.log.Error ("PublishMessages(), Connect failed! this.conn == null || !conn.IsOpen ");
                ReconnectToRMQ();
            } else { 
                var properties = Channel.CreateBasicProperties();
                properties.Persistent = true;
    
                Channel.BasicPublish (_exchangeName, routingKey, properties, message);
                //serviceInstance1.Publish(message, _rabbitOptions.ExchangeName, "", routingKey);
            }
        }
    }
    
    Task t2 = Task.Factory.StartNew(() =>
                {
                    while (true) { 
                        if (!concurrentQueue.IsEmpty)
                        {
                            JToken number;
                            while (concurrentQueue.TryDequeue(out number))
                            {
                                _rabbitMQ.PublishMessages(
                                    Encoding.ASCII.GetBytes(number.ToString()),
                                    "test"
                                );
                            }
                        } else
                        {
                            Thread.Sleep(1);
                        }
                    }
                });  
    
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    using Newtonsoft.Json;
    using System.Linq;
    
    namespace DataFlowExperiment.PipelinesLib
    {
    
        public class PipelineOne
        {
            private readonly IPipelineOneSteps steps;
    
            private readonly TransformBlock<string, XDocument> startBlock; // XML deserialize to Model
            private readonly TransformManyBlock<XDocument, string> toJsonMessagesBlock; // jsons generieren.
            private readonly ITargetBlock<string> resultCallback;
    
            public PipelineOne(IPipelineOneSteps steps, ITargetBlock<string> resultCallback = null)
            {
                this.steps = steps;
    
                startBlock = new TransformBlock<string, XDocument>(steps.Start);
                toJsonMessagesBlock = new TransformManyBlock<XDocument, string>(steps.ToJson);
    
                this.resultCallback = resultCallback ?? DataflowBlock.NullTarget<string>();
    
                startBlock.LinkTo(toJsonMessagesBlock, new DataflowLinkOptions { PropagateCompletion = true });
                toJsonMessagesBlock.LinkTo(this.resultCallback, new DataflowLinkOptions { PropagateCompletion = true }, x => !string.IsNullOrEmpty(x));
                toJsonMessagesBlock.LinkTo(DataflowBlock.NullTarget<string>(), new DataflowLinkOptions { PropagateCompletion = true });
            }
    
            public void Post(string input)
            {
                startBlock.Post(input);
            }
    
            public Task Close()
            {
                startBlock.Complete();
                return resultCallback.Completion;
            }
        }
    
        public interface IPipelineOneSteps
        {
            public XDocument Start(string input);
            public IEnumerable<string> ToJson(XDocument doc);
        }
    
        public class PipelineOneSteps : IPipelineOneSteps
        {
            private readonly JsonSerializer jsonSerializer;
    
            public PipelineOneSteps()
            {
                jsonSerializer = JsonSerializer.CreateDefault();
            }
    
            public XDocument Start(string input)
            {
                XDocument doc = XDocument.Parse(input);
                return doc;
            }
    
            public IEnumerable<string> ToJson(XDocument doc)
            {
                XNamespace ns = "api-com";
                var orders = doc.Root.Elements(ns + "ORDER");
    
                foreach (var order in orders)
                {
                    yield return JsonConvert.SerializeXNode(order);
                }
            }
        }
    }
    
    
    BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.867 (2004/?/20H1)
    Intel Core i9-10885H CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
    .NET Core SDK=5.0.202
      [Host]     : .NET Core 3.1.14 (CoreCLR 4.700.21.16201, CoreFX 4.700.21.16208), X64 RyuJIT
      DefaultJob : .NET Core 3.1.14 (CoreCLR 4.700.21.16201, CoreFX 4.700.21.16208), X64 RyuJIT