protected override void RunLoop() { using (var redisClient = clientsManager.GetReadOnlyClient()) { using (var subscription = redisClient.CreateSubscription()) { subscription.OnUnSubscribe = channel => Log.Debug("OnUnSubscribe: " + channel); subscription.OnMessage = (channel, msg) => { if (msg == WorkerStatus.StopCommand) { Log.Debug("Stop Command Issued"); if (Interlocked.CompareExchange(ref status, WorkerStatus.Stopped, WorkerStatus.Started) != WorkerStatus.Started) Interlocked.CompareExchange(ref status, WorkerStatus.Stopped, WorkerStatus.Stopping); Log.Debug("UnSubscribe From All Channels..."); subscription.UnSubscribeFromAllChannels(); //Un block thread. return; } this.IncrementMessageCount(1); var messageReceivedArgs = new MessageReceivedArgs {QueueName = msg}; this.MqServer.NotifyMessageReceived(messageReceivedArgs); }; subscription.SubscribeToChannels(QueueNames.TopicIn); //blocks thread } } }
// IList<WaitHandle> manualResetEvents = new List<WaitHandle>(); public override void NotifyMessageReceived(MessageReceivedArgs messageReceivedArgs) { var handlerThreadCount = this.MessageHandlerRegister.RegisteredHandlers[messageReceivedArgs.MessageType].Configuration.NoOfThreads; if (handlerThreadCount == 0) //// 0 => Threadpool { // Threadpool // Queue the item to execute using the thread pool. // TODO: Use Wait and Pulse; Use a incremental lock counter to ensure that all queued work items complete. // var manualResetEvent = new ManualResetEvent(false); // lock (manualResetEvents) // { // TODO: Verify that a lock is not required. // manualResetEvents.Add(manualResetEvent); Interlocked.Increment(ref threadPoolWorkItemCount); ThreadPool.QueueUserWorkItem(new WaitCallback(ExecuteUsingQueuedWorkItem), messageReceivedArgs); // TODO: How to wait for all tasks to complete using this method? // } /* * // TODO: Change Project Framework to 3.5 * // TODO: Wait for all queued work items to complete when stop is called, in DISPOSE method. * lock (manualResetEvents) * { * // After stop is called, set a flag that indicates pulse should be called when count == 0 * // TODO: Loop until count is 0; then pulse (Or, if already 0; pulse instantly) * WaitHandle.WaitAll(manualResetEvents.ToArray()); * }*/ } else { // Static Thread base.NotifyMessageReceived(messageReceivedArgs); } }
protected override void RunLoop() { // Use Long-Polling to retrieve messages from a specific SQS queue. while (Interlocked.CompareExchange(ref status, 0, 0) == WorkerStatus.Started) { Log.DebugFormat("Polling SQS Queue '{0}' for messages.", this.QueueName); var response = this.SqsClient.ReceiveMessage(this.QueueUrl, this.WaitTimeInSeconds, this.MaxNumberOfMessages, this.MessageVisibilityTimeout, "ApproximateReceiveCount"); // Blocks until timout, or msg received if (response.IsSetReceiveMessageResult() && response.ReceiveMessageResult.Message.Count > 0) { // Place the item in the ready to process queue, and notify workers that a new msg has arrived. Log.DebugFormat("Received {0} Message(s) from Queue '{1}'.", response.ReceiveMessageResult.Message.Count, this.QueueName); // Thread-safe local queue -> Provides access to msg reponse, and retrieving multiple msgs! foreach (var sqsMessage in response.ReceiveMessageResult.Message) { // TODO: Remember; Need to code so no problem if same message received twice... consider cache? // TODO: Need to verify Message MD5, and use 'IsSet()' methods to ensure the msg is valid. Earlier in process. if (sqsMessage.IsSetMD5OfBody() && !MessageSecurity.IsMd5Valid(sqsMessage.Body, sqsMessage.MD5OfBody)) { Log.WarnFormat("Message '{0}' has invalid MD5 signature, will not be processed."); continue; } var messageBytes = Convert.FromBase64String(sqsMessage.Body); // Set standard message properties var message = messageBytes.ToMessage(this.MessageType); if (sqsMessage.IsSetAttribute() && sqsMessage.Attribute.Count > 0) { foreach (var attribute in sqsMessage.Attribute) { if (attribute.Name == "ApproximateReceiveCount") { message.RetryAttempts = int.Parse(attribute.Value); break; } } } // Set SQS message properties var sqsMessageBody = message.Body as ISqsMessageBody; if (sqsMessageBody != null) { sqsMessageBody.ReceiptHandle = sqsMessage.ReceiptHandle; sqsMessageBody.QueueUrl = this.QueueUrl; sqsMessageBody.QueueName = this.QueueName; sqsMessageBody.VisibilityTimeout = this.MessageVisibilityTimeout; message.RetryAttempts += sqsMessageBody.PreviousRetryAttempts; } else { Log.WarnFormat("The message type '{0}' is using the AwsSqsQueueHandler, but does not implement 'ISqsMessageBody'. No AwsSqsMessageHandlerRegister pre,post or error message handlers will be executed.", this.MessageType.Name); } // ===================== this.MessageCoordinator.EnqueMessage(this.QueueName, message, this.MessageType); this.IncrementMessageCount(1); var messageReceivedArgs = new MessageReceivedArgs { MessageType = this.MessageType, QueueName = this.QueueName, MessageId = sqsMessage.MessageId }; this.MqServer.NotifyMessageReceived(messageReceivedArgs); } } } Log.DebugFormat("Stopped polling SQS queue: {0}", this.QueueName); }