//internal protected virtual async Task<TOutputMessage> PublishMessageAsync(string routing, TInputMessage message, LogTrackerContext tracker) //{ // return await this.PublishMessageAsync( // this.IsWaitReturn, // MessageBusConfig.DefaultWaitReplyTimeOut, // MessageBusConfig.DefaultMessageExpirationTimeout, // routing, // message, // MessageBusConfig.DefaultRetryCount, // MessageBusConfig.DefaultRetryWaitTime, // tracker); //} //internal protected virtual async Task<TOutputMessage> PublishMessageAsync(string routing, byte[] message, LogTrackerContext tracker) //{ // return await this.PublishMessageAsync( // this.IsWaitReturn, // MessageBusConfig.DefaultWaitReplyTimeOut, // MessageBusConfig.DefaultMessageExpirationTimeout, // routing, // message, // null, // MessageBusConfig.DefaultRetryCount, // MessageBusConfig.DefaultRetryWaitTime, // tracker); //} internal protected virtual async Task <TOutputMessage> PublishMessageAsync( bool isWaitReply, TimeSpan waitReplyTimeout, TimeSpan messageExpirationTimeout, string routing, TInputMessage message, int retryCount, TimeSpan retryWaitTimeout, LogTrackerContext tracker) { Dictionary <string, object> headers = new Dictionary <string, object>(); headers["INPUT-MESSAGE-TYPE"] = typeof(TInputMessage).FullName; if (this.IsWaitReturn) { headers["OUTPUT-MESSAGE-TYPE"] = typeof(TOutputMessage).FullName; } return(await this.PublishMessageAsync( isWaitReply, waitReplyTimeout, messageExpirationTimeout, routing, Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(message)), headers, retryCount, retryWaitTimeout, tracker)); }
protected override void ExecuteSubscriberProcess(BetTransactionMessage message, LogTrackerContext logtracker) { LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.THREAD_DATASLOT, logtracker); _logger.Info(message.Id); //Console.WriteLine(message.Id); return; }
public void Test_BasicThreadDataSlotStorage() { var context = LogTrackerContext.Create("UNITTEST", LogTrackerContextStorageTypeEnum.THREAD_DATASLOT); Assert.AreEqual( context.RequestId, LogTrackerContext.Current.RequestId); Assert.AreEqual( context.RequestStartTimeUTC, LogTrackerContext.Current.RequestStartTimeUTC); }
protected override OutputMessageBase ExecuteSubscriberProcess(BetTransactionMessage message, LogTrackerContext logtracker) { LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.THREAD_DATASLOT, logtracker); _logger.Info(message.Id); //throw new Exception("TEST"); //Console.Write("start: {0}", message.Id); //Task.Delay(1000 * 10).Wait(); //Console.Write("end: {0}", message.Id); return(new OutputMessageBase()); }
protected override void ExecuteSubscriberProcess(TimerMessage message, LogTrackerContext logtracker) { _logger.Info("Add Timer Task: {0}, {1}, {2}", message.ID, message.RouteKey, message.RunAt); lock (schedule) { this.schedule.Add(new MessagePack() { _message = message, _context = logtracker }); this.schedule.Sort((t1, t2) => { return(DateTime.Compare(t1._message.RunAt, t2._message.RunAt)); }); } this.outputWait.Set(); }
static void Main(string[] args) { LogTrackerLogger logger = new LogTrackerLogger(LogManager.GetCurrentClassLogger()); Guid guid1 = Guid.NewGuid(); DateTime dt1 = DateTime.UtcNow; Console.WriteLine(String.Format("Worker: request_id1: {0} | request_start_time_utc: {1}", guid1.ToString(), dt1)); LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.THREAD_DATASLOT, guid1.ToString(), dt1); MockZeus.Service.Mercury.TP.GBTP gb1 = new MockZeus.Service.Mercury.TP.GBTP(); gb1.GetBalance(); System.Threading.Thread.Sleep(1000); Guid guid2 = Guid.NewGuid(); DateTime dt2 = DateTime.UtcNow; Console.WriteLine(String.Format("Worker: request_id1: {0} | request_start_time_utc: {1}", guid2.ToString(), dt2)); LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.THREAD_DATASLOT, guid2.ToString(), dt2); MockZeus.Service.Mercury.TP.GBTP gb2 = new MockZeus.Service.Mercury.TP.GBTP(); gb2.GetBalance(); Console.ReadLine(); }
static void Main(string[] args) { //LogTrackerContext.Clean(); //// Logger WITHOUT logConttext - To GrayLog //Console.WriteLine("Logger WITHOUT logConttext - To GrayLog"); //LogTrackerLogger loggerWOCtxGL = new LogTrackerLogger(LogManager.GetLogger("ToGrayLog")); //loggerWOCtxGL.Info(new LogMessage() { Message = "This log has no context information from POC.Client" }); //Console.ReadLine(); //// Logger WITH explicit logConttext - To Gray Log //string request_id = Guid.NewGuid().ToString(); //DateTime utcNow = DateTime.UtcNow; //LogTrackerContext lgc = LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.NONE, request_id, utcNow); //Console.WriteLine("Logger WITH explicit logConttext - To Gray Log"); //LogTrackerLogger loggerWTHCtxGL = new LogTrackerLogger(LogManager.GetLogger("ToGrayLog"), lgc); //loggerWTHCtxGL.Info(new LogMessage() { Message = "This log has context information from POC.Client" }); //Console.ReadLine(); //LogTrackerContext.Clean(); //HttpClient client = new HttpClient(); HttpClient client = new HttpClient(new LogTrackerHandler()); client.BaseAddress = new Uri("http://localhost:31554/"); Console.WriteLine(client.GetAsync("/api/values").Result); Console.WriteLine(client.GetAsync("/api/values/123").Result); // 測試Init錯誤參數 LogTrackerContext wrong_request_id = LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.NONE, "", DateTime.UtcNow); LogTrackerContext wrong_start_time = LogTrackerContext.Init(LogTrackerContextStorageTypeEnum.NONE, Guid.NewGuid().ToString(), DateTime.MinValue); // 以下測試需要將LogTrackerHandler中的request_id或start_time如上改成錯誤參數進行測試 //HttpClient wrong_http_context = new HttpClient(new LogTrackerHandler()); //client.BaseAddress = new Uri("http://localhost:31554/"); //Console.WriteLine(wrong_http_context.GetAsync("/api/values").Result); //Console.WriteLine(wrong_http_context.GetAsync("/api/values/123").Result); }
public void Test_ThreadDataSlotStorage_MultiThreads() { List <Task> tasks = new List <Task>(); for (int i = 0; i < 10; i++) { tasks.Add(Task.Run(() => { //LogTrackerContext context = LogTrackerContext.Create("UNITTEST", LogTrackerContextStorageTypeEnum.THREAD_DATASLOT); for (int y = 0; y < 10; y++) { string current_request_id = Guid.NewGuid().ToString(); DateTime current_request_time = DateTime.UtcNow; LogTrackerContext context = LogTrackerContext.Init( LogTrackerContextStorageTypeEnum.THREAD_DATASLOT, current_request_id, current_request_time); this.TestContext.WriteLine("TID: {0}, Request-ID: {1}, Request-Time: {2}", Thread.CurrentThread.ManagedThreadId, context.RequestId, context.RequestStartTimeUTC); for (int x = 0; x < 10; x++) { Task.Delay(100).Wait(); Assert.AreEqual( current_request_id, LogTrackerContext.Current.RequestId); Assert.AreEqual( current_request_time, LogTrackerContext.Current.RequestStartTimeUTC); } } })); } Task.WaitAll(tasks.ToArray()); }
private void StartProcessSubscribedMessage(SubscriberProcess process) { //this._stop = false; //Stopwatch totalWatch = new Stopwatch(); //totalWatch.Start(); _logger.Trace("WorkerThread({0}) - start running...", Thread.CurrentThread.ManagedThreadId); //using (var connection = MessageBusConfig.DefaultConnectionFactory.CreateConnection()) //this.connectionFactory.CreateConnection()) using (var channel = this._connection.CreateModel()) { channel.QueueDeclare( queue: this.QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null); BasicGetResult result = null; while (this._stop == false) { try { result = channel.BasicGet(this.QueueName, false); if (result == null) { Task.Delay(MessageBusConfig.DefaultPullWaitTime).Wait(); continue; } _logger.Trace("WorkerThread({0}) - receive message: {1}", Thread.CurrentThread.ManagedThreadId, result.BasicProperties.MessageId); } catch (Exception ex) { if (!_connection.IsOpen || channel.IsClosed) { _logger.Trace("WorkerThread({0}) message channel is closed. Reason: {1}", Thread.CurrentThread.ManagedThreadId, _connection.IsOpen ? channel.CloseReason : _connection.CloseReason); } this._stop = true; this._is_restart = true; _logger.Warn(ex, "dequeue exception, restart subscriber..."); result = null; break; } TOutputMessage response = null; var body = result.Body; var props = result.BasicProperties; bool current_reply = (string.IsNullOrEmpty(props.ReplyTo) == false); var replyProps = channel.CreateBasicProperties(); replyProps.CorrelationId = props.CorrelationId; LogTrackerContext logtracker = null; if (props.Headers == null || props.Headers[LogTrackerContext._KEY_REQUEST_ID] == null) { // message without logtracker context info logtracker = LogTrackerContext.Create(this.GetType().FullName, LogTrackerContextStorageTypeEnum.NONE); } else { string req_id = Encoding.UTF8.GetString((byte[])props.Headers[LogTrackerContext._KEY_REQUEST_ID]); DateTime req_time = DateTime.Parse(Encoding.UTF8.GetString((byte[])props.Headers[LogTrackerContext._KEY_REQUEST_START_UTCTIME])).ToUniversalTime(); logtracker = LogTrackerContext.Init( LogTrackerContextStorageTypeEnum.NONE, req_id, req_time); } try { TInputMessage request = JsonConvert.DeserializeObject <TInputMessage>(Encoding.Unicode.GetString(body)); _logger.Trace("WorkerThread({0}) - before processing message: {1}", Thread.CurrentThread.ManagedThreadId, props.MessageId); response = process(request, logtracker); _logger.Trace("WorkerThread({0}) - message was processed: {1}", Thread.CurrentThread.ManagedThreadId, props.MessageId); } catch (Exception e) { response = new TOutputMessage() { exception = e.ToString() }; _logger.Warn(e, "WorkerThread({0}) - process message with exception: {1}, ex: {2}", Thread.CurrentThread.ManagedThreadId, props.MessageId, e); } try { if (current_reply) { byte[] responseBytes = null;//Encoding.UTF8.GetBytes(response); if (response != null) { responseBytes = Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(response)); } channel.BasicPublish( exchange: "", routingKey: props.ReplyTo, basicProperties: replyProps, body: responseBytes); } channel.BasicAck( deliveryTag: result.DeliveryTag, multiple: false); } catch (Exception ex) { // connection fail while return message or ack. // just shutdown and ignore it. non-return ack will be ignore, message will retry in next time if (!_connection.IsOpen || channel.IsClosed) { _logger.Trace("WorkerThread({0}) message channel is closed. Reason: {1}", Thread.CurrentThread.ManagedThreadId, _connection.IsOpen ? channel.CloseReason : _connection.CloseReason); } this._stop = true; this._is_restart = true; _logger.Warn(ex, "dequeue exception, restart subscriber..."); result = null; break; } } } _logger.Info("WorkerThread({0}) - {1} (restarting: {2}).", Thread.CurrentThread.ManagedThreadId, this.Status, this._is_restart); //this._stop?"stopped":"restarting"); }
protected override ResponseMessage ExecuteSubscriberProcess(RequestMessage message, LogTrackerContext logtracker) { Interlocked.Increment(ref count); return(new ResponseMessage() { result_json = message.input_json }); }
/// <summary> /// NOTE: /// 所有的 PublishMessageAsync( ) 系列 overloading method 裡,這個 method 是真正在處理訊息發送的部分。 /// 其餘的 overloading 目的只是做預設參數的處理 /// </summary> /// <param name="isWaitReply"></param> /// <param name="waitReplyTimeout"></param> /// <param name="messageExpirationTimeout"></param> /// <param name="routing"></param> /// <param name="messageBody"></param> /// <param name="messageHeaders"></param> /// <param name="retryCount"></param> /// <param name="retryWaitTimeout"></param> /// <param name="tracker"></param> /// <returns></returns> internal protected virtual async Task <TOutputMessage> PublishMessageAsync( bool isWaitReply, TimeSpan waitReplyTimeout, TimeSpan messageExpirationTimeout, string routing, //TInputMessage message, byte[] messageBody, Dictionary <string, object> messageHeaders, int retryCount, TimeSpan retryWaitTimeout, LogTrackerContext tracker) { bool isPublishComplete = false; ConnectionFactory connFac = MessageBusConfig.DefaultConnectionFactory; while (true) { if (retryCount <= 0) { // 已經超出最大的重新連線嘗試次數。 throw new Exception("RetryLimitException"); } try { using (var connection = MessageBusConfig.DefaultConnectionFactory.CreateConnection(connFac.HostName.Split(','), this.ConnectionName)) using (var channel = connection.CreateModel()) { string replyQueueName = null; if (this.BusType == MessageBusTypeEnum.QUEUE) { channel.QueueDeclare( //queue: routing, queue: this.QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null); } else if (this.BusType == MessageBusTypeEnum.EXCHANGE) { channel.ExchangeDeclare( this.ExchangeName, this.ExchangeType, true, false, null); } else { throw new InvalidOperationException(); } if (isWaitReply) { replyQueueName = channel.QueueDeclare().QueueName; //consumer = new QueueingBasicConsumer(channel); //channel.BasicConsume( // queue: replyQueueName, // noAck: true, // consumer: consumer); } IBasicProperties props = channel.CreateBasicProperties(); props.ContentType = "application/json"; props.Expiration = messageExpirationTimeout.TotalMilliseconds.ToString(); if (tracker == null) { tracker = LogTrackerContext.Create( this.GetType().Name, LogTrackerContextStorageTypeEnum.NONE); } props.Headers = (messageHeaders == null)? new Dictionary <string, object>() : new Dictionary <string, object>(messageHeaders); props.Headers[LogTrackerContext._KEY_REQUEST_ID] = tracker.RequestId; props.Headers[LogTrackerContext._KEY_REQUEST_START_UTCTIME] = tracker.RequestStartTimeUTC_Text; if (isWaitReply) { //message.correlationId = props.CorrelationId = Guid.NewGuid().ToString("N"); props.ReplyTo = replyQueueName; } try { if (this.BusType == MessageBusTypeEnum.EXCHANGE) { channel.BasicPublish( exchange: this.ExchangeName ?? "", routingKey: routing, basicProperties: props, //body: Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(message))); body: messageBody); } else if (this.BusType == MessageBusTypeEnum.QUEUE) { channel.BasicPublish( exchange: "", routingKey: this.QueueName, basicProperties: props, //body: Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(message))); body: messageBody); } isPublishComplete = true; if (isWaitReply) { BasicGetResult result = null; DateTime until = DateTime.Now.Add(waitReplyTimeout); while (result == null && DateTime.Now < until) { result = channel.BasicGet(replyQueueName, true); if (result == null) { Task.Delay(MessageBusConfig.DefaultPullWaitTime).Wait(); } } if (result != null) { // done, receive response message TOutputMessage response = JsonConvert.DeserializeObject <TOutputMessage>(Encoding.Unicode.GetString(result.Body)); return(response); } else { // timeout, do not wait anymore throw new TimeoutException(string.Format( "MessageBus 沒有在訊息指定的時間內 ({0}) 收到 ResponseMessage 回覆。", waitReplyTimeout)); } } break; } finally { if (isWaitReply && string.IsNullOrEmpty(replyQueueName) == false) { channel.QueueDelete(replyQueueName); } } } } catch (Exception ex) { // 如果訊息已經成功送出,只是在等待 response 時發生連線錯誤,則不會進行 Retry, 會原封不動地把 exception 丟回給呼叫端。 // 由呼叫端決定該如何進行下一個步驟。 if (isPublishComplete) { throw; } // connection fail. _logger.Warn(ex, "Retry (left: {0}) ...", retryCount); //Console.WriteLine("Retry.."); retryCount--; await Task.Delay(retryWaitTimeout); continue; } finally { } } return(null); }
protected abstract TOutputMessage ExecuteSubscriberProcess(TInputMessage message, LogTrackerContext logtracker);
//private bool _stop_forwarder = false; //public void StopForwarder() //{ // _stop_forwarder = true; // this.outputWait.Set(); //} private void ForwardMessage() { //_stop_forwarder = false; //while (_stop_forwarder == false) while (this.Status != WorkerStatusEnum.STOPPED) { while (this.schedule.Count > 0) { MessagePack msgpack = this.schedule[0]; TimerMessage msg = msgpack._message; LogTrackerContext ctx = msgpack._context; msg.RunAt = msg.RunAt.ToUniversalTime(); MessageClientBase <InputMessageBase> mcb = null; if (string.IsNullOrEmpty(msg.QueueName)) { mcb = new MessageClientBase <InputMessageBase>(msg.ExchangeName, msg.ExchangeType); } else { mcb = new MessageClientBase <InputMessageBase>(msg.QueueName); } if (msg.RunAt <= DateTime.UtcNow) { // do expired //Console.WriteLine("Run Expired Task: {0}, {1}, {2}", msg.ID, msg.RouteKey, msg.RunAt); _logger.Info("Run Expired Task: {0}, {1}, {2}", msg.ID, msg.RouteKey, msg.RunAt); lock (schedule) schedule.Remove(msgpack); mcb.PublishMessageAsync( mcb.IsWaitReturn, MessageBusConfig.DefaultWaitReplyTimeOut, MessageBusConfig.DefaultMessageExpirationTimeout, msg.RouteKey, Encoding.Unicode.GetBytes(msg.MessageText), new Dictionary <string, object>() { { "INPUT-MESSAGE-TYPE", msg.MessageType } }, MessageBusConfig.DefaultRetryCount, MessageBusConfig.DefaultRetryWaitTime, ctx).Wait(); } else if (outputWait.WaitOne(msg.RunAt - DateTime.UtcNow) == false) { // do now // Console.WriteLine("Run OnTime Task: {0}, {1}, {2}", msg.ID, msg.RouteKey, msg.RunAt); _logger.Info("Run OnTime Task: {0}, {1}, {2}", msg.ID, msg.RouteKey, msg.RunAt); lock (schedule) schedule.Remove(msgpack); //stp.PublishMessage(msg.RouteKey, msg); mcb.PublishMessageAsync( mcb.IsWaitReturn, MessageBusConfig.DefaultWaitReplyTimeOut, MessageBusConfig.DefaultMessageExpirationTimeout, msg.RouteKey, Encoding.Unicode.GetBytes(msg.MessageText), null, MessageBusConfig.DefaultRetryCount, MessageBusConfig.DefaultRetryWaitTime, ctx).Wait(); } //else //{ // Console.WriteLine("Next Job:"); // lock (schedule) foreach (MessagePack m in schedule) // { // Console.WriteLine("- [{0}][{1}], {2}", m._message.ID, m._message.RouteKey, m._message.RunAt); // } //} mcb.Dispose(); if (this.Status == WorkerStatusEnum.STOPPED) { // ToDo: do shutdown work return; } } this.outputWait.WaitOne(); } }
static void Main(string[] args) { string mode = (args.Length == 0) ? "ASYNC" : args[0].ToUpper(); Console.WriteLine("Start in {0} mode.", mode); BetMessageClient bmc = null; BetRpcClient brc = null; BetTimerClient btc = null; LogTrackerContext.Create("POC/BetTransactions.Client", LogTrackerContextStorageTypeEnum.THREAD_DATASLOT); _logger.Info("Init..."); switch (mode) { case "ASYNC": bmc = new BetMessageClient(); break; case "SYNC": brc = new BetRpcClient(); break; case "TIMER": btc = new BetTimerClient(); break; } Stopwatch timer = new Stopwatch(); timer.Start(); for (int i = 1; i <= 1000000; i++) { BetTransactionMessage btm = new BetTransactionMessage() { Id = string.Format("{0}-{1}", i, Guid.NewGuid()) }; switch (mode) { case "ASYNC": bmc.PublishAsync("letou", btm).Wait(); break; case "SYNC": // async sample //try //{ // OutputMessageBase omb = brc.CallAsync("letou", btm).Result; //} //catch(AggregateException ae) //{ // foreach(Exception ex in ae.InnerExceptions) // if (ex is RpcServerException) Console.WriteLine("RpcServerException.Source: {0}", (ex as RpcServerException).Source); //} // sync sample try { OutputMessageBase omb = brc.Call("letou", btm); } catch (RpcServerException rse) { Console.WriteLine("\r\nRpcServerException: {0}", rse.Source); } break; case "TIMER": btc.PublishAsync("letou", btm, TimeSpan.FromSeconds(50)).Wait(); break; } if (args.Length > 1 && args[1] == "delay") { Task.Delay(300).Wait(); } Console.Write('.'); if (i % 100 == 0) { Console.WriteLine(); Console.WriteLine("Message Published: {0}, {1:0.00} msg/sec", i, 100 * 1000 / timer.ElapsedMilliseconds); timer.Restart(); } } }