工做中要求使用RabbitMQ,以Windows Service 模式啓動,中間有遇到一些問題,網上大部分博客有誤導傾向, 在這裏作一個簡單的記錄,以避免後面的人走坑;css
1.html
自動從新鏈接,不須要手動處理自動鏈接 測試
AutomaticRecoveryEnabled = true //斷開自動從新鏈接spa
2.由於是Windows Service ,與控制檯程序不一樣,如果像Demo中直接使用Received ,那麼可能只會接收一次消息,而後程序執行完畢退出操作系統
後來我就使用了While(true),當時測試能解決問題,後來發現運行久了沒有消息接收會時不時的斷開鏈接,出現錯誤消息提示:code
【ErrorType】System.IO.EndOfStreamException 【TargetSite】T Dequeue() 【Message】SharedQueue closed 【Source】RabbitMQ.Client 【StackTrace】 at RabbitMQ.Util.SharedQueue`1.Dequeue() at ******
開始覺得是RabbitMQ.Net的版本問題,觀察對比了幾回發現並非這個問題,高版本的程序也存在這個問題,低版本的也有,並且只有在Windows Service中才會有這個錯誤,直接Debug測試時正常的,htm
這個錯誤很容易被忽略,應該感受本身Debug沒有問題,怎麼到客戶那裏Windows Service就出錯了,會覺得是安裝包或者是客戶電腦的問題,後來發現是由於While(true)的問題;blog
網上這個問題的不少答案都是說是確認消息 自動確認又手動確認,反正不少,後來發現是沒有用事件的緣由;隊列
在http://www.cnblogs.com/maanshancss/p/7905976.html 也提到了不用while(true),我開始還覺得只是異常處理部分做者沒有處理呢,實際上須要另一種寫法,針對的Window Service 的,文章後面會貼出來源碼;事件
3.須要理解XP和Win7 etc. 不一樣操做系統中 Window Service 帳戶的區別
4.參考http://www.cnblogs.com/maanshancss/p/7905976.html
中的內容,有些是須要注意的
try { string amqEndpoint = System.Configuration.ConfigurationManager.AppSettings["MQEndpoint"].ToString(); string amqUsername = System.Configuration.ConfigurationManager.AppSettings["MQUserName"].ToString(); string amqPassword = System.Configuration.ConfigurationManager.AppSettings["MQPassword"].ToString(); var amqName = System.Configuration.ConfigurationManager.AppSettings["MQName"].ToString(); var exchangeType = "direct"; var uri = new Uri("amqp://" + amqEndpoint + "/"); var factory = new ConnectionFactory { UserName = amqUsername, Password = amqPassword, RequestedHeartbeat = 60, Endpoint = new AmqpTcpEndpoint(uri), AutomaticRecoveryEnabled = true //斷開自動從新鏈接 }; var connection = factory.CreateConnection(); var channel = connection.CreateModel(); channel.QueueDeclare(queue: amqName, durable: true, exclusive: false, autoDelete: false, arguments: null); //建立基於該隊列的消費者,綁定事件 var consumer = new EventingBasicConsumer(channel); //綁定消費者 channel.BasicConsume(queue: amqName, //隊列名 noAck: false, //false:手動應答;true:自動應答 consumer: consumer); consumer.Received += (model, ea) => { try { //TOOD 驗證程序退出後消費者是否退出去了 var body = ea.Body; //消息主體 var message = Encoding.UTF8.GetString(body); Logger.WriteAndShowLog(message); // Method(message); channel.BasicAck(ea.DeliveryTag, false); } catch (RabbitMQ.Client.Exceptions.OperationInterruptedException ex1) { Logger.CreateErrorLog(ex1, "OperationInterruptedException"); Thread.Sleep(5000); channel.BasicNack(ea.DeliveryTag, false, true); } catch (Exception ex) { Logger.CreateErrorLog(ex, "Exception"); Thread.Sleep(5000); channel.BasicNack(ea.DeliveryTag, false, true); } }; Console.ReadLine(); } catch (System.Exception ex) { Logger.CreateErrorLog(ex); Console.ReadLine(); }
與Demo不一樣的地方
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
這樣纔不會直接消失;