public virtual async Task StartWorkersAsync(SubscriberProcess process, int worker_count) { await this.StartWorkersAsync( process, worker_count, MessageBusConfig.DefaultRetryCount, MessageBusConfig.DefaultRetryWaitTime); }
public void StartWorkers(WorkerProcess process, int worker_count) { SubscriberProcess x = (req, tracker) => { this.CurrentZeusRequestId = req.request_id; return(process(req)); }; this.StartWorkersAsync( (SubscriberProcess)((req, tracker) => { this.CurrentZeusRequestId = req.request_id; return(process(req)); }), worker_count).Wait(); }
protected virtual async Task StartWorkersAsync(SubscriberProcess process, int worker_count, int retry_count, TimeSpan retry_timeout) { lock (this._sync_root) { //if (this._worker_running) throw new InvalidOperationException("worker already started."); //this._worker_running = true; if (this.Status != WorkerStatusEnum.STOPPED) { throw new InvalidOperationException(); } this.Status = WorkerStatusEnum.STARTING; } //模擬測試 connection 建立過久,導致 worker 長時間處於 starting 狀態的問題。這狀態下呼叫 stopworker 會引發 exception //Task.Delay(5000).Wait(); ConnectionFactory cf = MessageBusConfig.DefaultConnectionFactory; while (retry_count > 0) { try { this._connection = MessageBusConfig.DefaultConnectionFactory.CreateConnection(cf.HostName.Split(','), this.ConnectionName); } catch { retry_count--; _logger.Warn("connection create fail. restarting..."); Task.Delay(retry_timeout).Wait(); continue; } try { // TASK implement //this._stop = false; //this._is_restart = false; //Task[] tasks = new Task[worker_count]; //for (int index = 0; index < worker_count; index++) //{ // tasks[index] = Task.Run(() => { this.StartProcessSubscribedMessage(process); }); //} //this.Status = WorkerStatusEnum.STARTED; //foreach (Task t in tasks) await t; //this.Status = WorkerStatusEnum.STOPPED; this._stop = false; this._is_restart = false; //Task[] tasks = new Task[worker_count]; Thread[] threads = new Thread[worker_count]; for (int index = 0; index < worker_count; index++) { //tasks[index] = Task.Run(() => { this.StartProcessSubscribedMessage(process); }); threads[index] = new Thread(() => { this.StartProcessSubscribedMessage(process); }); threads[index].Start(); } this.Status = WorkerStatusEnum.STARTED; //foreach (Task t in tasks) await t; _logger.Info("waiting all worker threads to STOP..."); await Task.Run(() => { foreach (Thread t in threads) { t.Join(); } }); this.Status = WorkerStatusEnum.STOPPED; } catch (Exception ex) { _logger.Warn(ex, "waiting task(s) exception. shutdown and retry..."); this._is_restart = true; this._stop = true; } if (this._is_restart == false) { break; } retry_count--; await Task.Delay(retry_timeout); _logger.Warn("connection fail, restarting..."); } lock (this._sync_root) { //this._worker_running = false; this.Status = WorkerStatusEnum.STOPPED; } if (this._is_restart && retry_count == 0) { throw new Exception("Retry 次數已超過,不再重新嘗試連線。"); } }
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"); }