void deliveryWork(Semaphore deliverySemaphore, IMessageDeliveryQueue queue) { if (deliverySemaphore.WaitOne(TimeSpan.FromSeconds(1), true)) { bool release = true; try { CommittableTransaction ct = new CommittableTransaction(); Transaction.Current = ct; MessageDelivery md = queue.Dequeue(TimeSpan.FromSeconds(DEQUEUE_TIMEOUT_SECONDS)); if (md != null) { DeliveryWork work = new DeliveryWork(ct, md, deliverySemaphore); release = false; ThreadPool.QueueUserWorkItem((deliverWork) => { try { DoSafely(() => DeliverOne((DeliveryWork)deliverWork)); } finally { work.DeliverySemaphore.Release(); } }, work); } else { ct.Dispose(); } } finally { if (release) { deliverySemaphore.Release(); } Transaction.Current = null; } } }
protected void DeliverOne(DeliveryWork work) { System.Transactions.Transaction.Current = work.Transaction; try { using (work.Transaction) { try { MessageDelivery delivery = work.Delivery; if (delivery != null) { if (!delivery.IsExpired) { if (delivery.TimeToProcess != null) { int mDelay = (int)(delivery.TimeToProcess.Value - DateTime.Now).TotalMilliseconds; if (mDelay > 0) { System.Diagnostics.Debug.WriteLine("Time to process is " + mDelay + " milliseconds away. Requeuing in " + FUTURE_SLEEP_MS); Thread.Sleep(FUTURE_SLEEP_MS); // Sleep briefly in case we are in a loop of future messages, should be a little smarter QueueRetry(delivery); return; } } SubscriptionEndpoint endpoint = Runtime.GetSubscription(delivery.SubscriptionEndpointId); if (endpoint != null) { Dispatcher dispatcher = endpoint.Dispatcher; if (dispatcher != null) { dispatcher.Dispatch(delivery); } else { throw new InvalidOperationException("Dispatcher is not set"); } } else { System.Diagnostics.Debug.WriteLine(String.Format(CultureInfo.InvariantCulture, "Subscription {0} no longer exists. Skipping delivery.", delivery.SubscriptionEndpointId)); } NotifyDelivery(delivery); } else { QueueFail(delivery, new TimeoutException("The Message expired before it could be delivered.")); NotifyExpired(delivery); NotifyFailure(delivery, true); } } work.Transaction.Commit(); } catch (Exception ex) { try { bool retry = !work.Delivery.RetriesMaxed; if (retry) { QueueRetry(work.Delivery, ex); } else { QueueFail(work.Delivery, ex); } NotifyUnhandledException(ex, false); NotifyFailure(work.Delivery, !retry); work.Transaction.Commit(); } catch (Exception innerEx) { throw new DeliveryException("Unhandled exception while attempting to requeue a message: " + innerEx, ex); } throw new DeliveryException("Unhandled exception while attempting to deliver a message.", ex); } } } finally { work.Transaction.Dispose(); System.Transactions.Transaction.Current = null; } }