예제 #1
0
        /// <summary>
        /// Gets called by the provider to notify this subscriber about a new inter-role communication event.
        /// </summary>
        /// <param name="e">The received inter-role communication event.</param>
        public void OnNext(InterRoleCommunicationEvent e)
        {
            Guard.ArgumentNotNull(e, "e");
            var callToken = TraceManager.WorkerRoleComponent.TraceIn(e.FromInstanceID, e.ToInstanceID);

            try
            {
                if (this.owner != null && e.Payload != null)
                {
                    if (e.Payload is PersistenceQueueItemInfo)
                    {
                        HandlePersistenceQueueItem(e.Payload as PersistenceQueueItemInfo);
                        return;
                    }

                    if (e.Payload is CloudQueueWorkDetectedTriggerEvent)
                    {
                        HandleQueueWorkDetectedTriggerEvent(e.Payload as CloudQueueWorkDetectedTriggerEvent);
                        return;
                    }
                }
            }
            finally
            {
                TraceManager.WorkerRoleComponent.TraceOut(callToken);
            }
        }
예제 #2
0
        private void NotifySubscribers(InterRoleCommunicationEvent e)
        {
            Guard.ArgumentNotNull(e, "e");

            // Invokes the specified action for each subscriber.
            Parallel.ForEach(this.subscribers, ((subscriber) =>
            {
                try
                {
                    // Notify the subscriber.
                    subscriber.Key.OnNext(e);
                }
                catch (Exception ex)
                {
                    // Do not allow any subscriber to generate a fault and affect other subscribers.
                    try
                    {
                        // Notifies the subscriber that the event provider has experienced an error condition.
                        subscriber.Key.OnError(ex);
                    }
                    catch (Exception fault)
                    {
                        // Log an error.
                        TraceManager.ServiceComponent.TraceError(fault);
                    }
                }
            }));
        }
        public void TestSingleEventWithCompetingConsumers()
        {
            var ircSettings = new InterRoleCommunicationSettings() { UseCompetingConsumers = true, EventWaitTimeout = TimeSpan.FromSeconds(10) };

            using (InterRoleCommunicationExtension irc1 = new InterRoleCommunicationExtension(topicEndpoint, ircSettings))
            using (InterRoleCommunicationExtension irc2 = new InterRoleCommunicationExtension(topicEndpoint, ircSettings))
            using (InterRoleCommunicationExtension irc3 = new InterRoleCommunicationExtension(topicEndpoint, ircSettings))
            using (InterRoleCommunicationExtension irc4 = new InterRoleCommunicationExtension(topicEndpoint, ircSettings))
            {
                var subscriber1 = new EventCountingSubscriber();

                irc1.Subscribe(subscriber1);
                irc2.Subscribe(subscriber1);
                irc3.Subscribe(subscriber1);
                irc4.Subscribe(subscriber1);

                InterRoleCommunicationEvent ev = new InterRoleCommunicationEvent(new RoleGracefulRecycleEvent(typeof(TopicBasedInterRoleCommunicationTests).FullName));

                irc1.Publish(ev);
                irc1.Publish(ev);
                irc1.Publish(ev);

                Thread.Sleep(irc4.Settings.EventWaitTimeout.Add(TimeSpan.FromSeconds(5)));

                Assert.AreEqual<int>(3, subscriber1.OnNextCount);
            }
        }
        protected void startTestButton_Click(object sender, EventArgs e)
        {
            TraceManager.WebRoleComponent.TraceIn();

            try
            {
                TestRunStartEvent startEvent = new TestRunStartEvent()
                {
                    TestRunID           = Guid.Parse(this.testRunIDTextBox.Text),
                    MessageCount        = Convert.ToInt32(this.messageCountTextBox.Text),
                    MessageSize         = Convert.ToInt32(this.messageSizeDropDown.Text),
                    EnableAsyncPublish  = this.publishAsyncCheckbox.Checked,
                    EnableAsyncDispatch = this.enableAsyncDispatchCheckbox.Checked,
                    RequireTopicCleanup = this.requireTopicCleanupCheckbox.Checked,
                    PurgeTraceLogTable  = this.purgeTraceLogTableCheckbox.Checked
                };

                var targetInstance = RoleEnvironment.Roles.Where(r => { return(r.Value != RoleEnvironment.CurrentRoleInstance.Role); }).
                                     SelectMany(i => i.Value.Instances).OrderBy(inst => { return(CommonFuncs.GetRoleInstanceIndex(inst.Id)); }).Take(1).
                                     FirstOrDefault();

                TraceManager.WebRoleComponent.TraceInfo("Sending an unicast IRC event to role instance ID {0}", targetInstance.Id);

                var ircEvent = new InterRoleCommunicationEvent(startEvent, roleInstanceID: targetInstance.Id);
                Global.InterRoleCommunicator.Publish(ircEvent);

                this.panelInfo.Visible = true;
            }
            catch (Exception ex)
            {
                this.labelExceptionDetails.Text = ExceptionTextFormatter.Format(ex);
                this.panelException.Visible     = true;
            }
        }
예제 #5
0
 /// <summary>
 /// Publishes the specified inter-role communication event into publish/subscribe messaging infrastructure.
 /// </summary>
 /// <param name="e">The inter-role communication event to be published.</param>
 public void Publish(InterRoleCommunicationEvent e)
 {
     // Wrap a call to the Publish into a retry policy-aware scope. This is because NetEventRelayBinding may return a fault if there are no
     // subscribers listening on the Service Bus URI. This behavior may be changed in the future releases of the Windows Azure Service Bus.
     Publisher.RetryPolicy.ExecuteAction(() =>
     {
         Publisher.Client.Publish(e);
     });
 }
        /// <summary>
        /// Receives a notification when a new inter-role communication event occurs.
        /// </summary>
        /// <param name="e">The instance of the inter-role communication event received from the underlying messaging system.</param>
        void IObserver <InterRoleCommunicationEvent> .OnNext(InterRoleCommunicationEvent e)
        {
            if (e != null && e.Payload != null)
            {
                T payload = e.Payload as T;

                if (payload != null)
                {
                    OnNext(payload);
                }
            }
        }
예제 #7
0
        private void OnPersistDataStreamCompleted(PersistenceQueueItemInfo queueItemInfo)
        {
            var callToken = TraceManager.WorkerRoleComponent.TraceIn(queueItemInfo.QueueItemId, queueItemInfo.QueueItemType, queueItemInfo.QueueItemSize);

            IInterRoleCommunicationExtension interCommExtension = Extensions.Find <IInterRoleCommunicationExtension>();

            if (interCommExtension != null)
            {
                InterRoleCommunicationEvent e = new InterRoleCommunicationEvent(queueItemInfo);
                interCommExtension.Publish(e);
            }

            TraceManager.WorkerRoleComponent.TraceOut(callToken);
        }
        public void TestSingleEvent()
        {
            using (InterRoleCommunicationExtension ircExtension = new InterRoleCommunicationExtension(topicEndpoint, new InterRoleCommunicationSettings() { EnableCarbonCopy = true }))
            {
                var subscriber1 = new EventCountingSubscriber();
                ircExtension.Subscribe(subscriber1);

                InterRoleCommunicationEvent ev = new InterRoleCommunicationEvent(new RoleGracefulRecycleEvent(typeof(TopicBasedInterRoleCommunicationTests).FullName));
                ircExtension.Publish(ev);

                Thread.Sleep(ircExtension.Settings.EventWaitTimeout.Add(TimeSpan.FromSeconds(5)));

                Assert.AreEqual<int>(1, subscriber1.OnNextCount);
            }
        }
예제 #9
0
        /// <summary>
        /// Publishes the specified inter-role communication event into publish/subscribe messaging infrastructure.
        /// </summary>
        /// <param name="e">The inter-role communication event to be published.</param>
        public void Publish(InterRoleCommunicationEvent e)
        {
            Guard.ArgumentNotNull(e, "e");

            var eventMsg = BrokeredMessage.CreateMessage(e);

            // Configure event routing properties.
            eventMsg.Properties[MsgCtxPropNameFromInstanceID] = e.FromInstanceID = this.senderInstanceID;
            eventMsg.Properties[MsgCtxPropNameToInstanceID]   = String.IsNullOrEmpty(e.ToInstanceID) ? MsgCtxPropValueAny : e.ToInstanceID;

            // Configure other message properties and settings.
            eventMsg.TimeToLive = this.settings.EventTimeToLive;

            // Send the event asynchronously.
            this.sendAction.BeginInvoke(eventMsg, this.endSend, null);
        }
예제 #10
0
        /// <summary>
        /// Gets called by the provider to notify this subscriber about a new inter-role communication event.
        /// </summary>
        /// <param name="e">The received inter-role communication event.</param>
        public void OnNext(InterRoleCommunicationEvent e)
        {
            var callToken = TraceManager.WorkerRoleComponent.TraceIn(e.FromInstanceID, e.ToInstanceID);

            if (this.owner != null)
            {
                PersistenceQueueItemInfo queueItemInfo = e.Payload as PersistenceQueueItemInfo;

                if (queueItemInfo != null)
                {
                    HandlePersistenceQueueItem(queueItemInfo);
                }
            }

            TraceManager.WorkerRoleComponent.TraceOut(callToken);
        }
예제 #11
0
        private void NotifySubscribers(InterRoleCommunicationEvent e)
        {
            Guard.ArgumentNotNull(e, "e");

#if PERF_TEST
            using (TraceManager.ServiceComponent.TraceScope("Notifying all subscribers", e.From, e.To))
#endif
            {
                Action <IObserver <InterRoleCommunicationEvent> > notifyAction = ((subscriber) =>
                {
                    try
                    {
                        // Notify the subscriber.
                        subscriber.OnNext(e);
                    }
                    catch (Exception ex)
                    {
                        // Do not allow any subscriber to generate a fault and affect other subscribers.
                        try
                        {
                            // Notifies the subscriber that the event provider has experienced an error condition.
                            subscriber.OnError(ex);
                        }
                        catch (Exception fault)
                        {
                            // Log an error.
                            TraceManager.ServiceComponent.TraceError(fault);
                        }
                    }
                });

                // Only parallelize when enabled and there is more than 1 active subscribers.
                if (this.Settings.EnableParallelDispatch && this.subscribers.Count > 1)
                {
                    // Invokes the specified action for each subscriber in parallel.
                    Parallel.ForEach(this.subscribers, ((s) => notifyAction(s.Key)));
                }
                else
                {
                    foreach (var s in this.subscribers)
                    {
                        notifyAction(s.Key);
                    }
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Multicasts the specified inter-role communication event to one or more subscribers.
        /// </summary>
        /// <param name="e">The inter-role communication event to be delivered to the subscribers.</param>
        public void Publish(InterRoleCommunicationEvent e)
        {
            // Validate input parameters.
            Guard.ArgumentNotNull(e, "e");

            // Log an entry point.
            var callToken = TraceManager.ServiceComponent.TraceIn(e.From);

            try
            {
                // Query all registered subscribers using query parallelization provided by PLINQ.
                var subscribers = from s in this.subscribers.AsParallel().AsUnordered() select s;

                // Invokes the specified action for each subscriber.
                subscribers.ForAll((subscriber) =>
                {
                    try
                    {
                        // Notify the subscriber.
                        subscriber.OnNext(e);
                    }
                    catch (Exception ex)
                    {
                        // Do not allow any subscriber to generate a fault and affect other subscribers.
                        try
                        {
                            // Notifies the subscriber that the event provider has experienced an error condition.
                            subscriber.OnError(ex);
                        }
                        catch (Exception fault)
                        {
                            // Log an error.
                            TraceManager.ServiceComponent.TraceError(fault);
                        }
                    }
                });
            }
            finally
            {
                // Log an exit point.
                TraceManager.ServiceComponent.TraceOut(callToken);
            }
        }
        public void TestSingleEventWithNetworkFaultSimulation()
        {
            try
            {
                using (InterRoleCommunicationExtension ircExtension = new InterRoleCommunicationExtension(topicEndpoint, new InterRoleCommunicationSettings() { EnableCarbonCopy = true, EnableAsyncPublish = false, EventWaitTimeout = TimeSpan.FromSeconds(3) }))
                {
                    bool retryOccurred = false;

                    ircExtension.Settings.RetryPolicy.RetryOccurred += (currentRetryCount, ex, delay) =>
                    {
                        retryOccurred = true;
                        NetworkUtility.EnableNetworkAdapter();
                    };

                    var subscriber1 = new EventCountingSubscriber();
                    ircExtension.Subscribe(subscriber1);

                    NetworkUtility.DisableNetworkAdapter();

                    InterRoleCommunicationEvent ev = new InterRoleCommunicationEvent(new RoleGracefulRecycleEvent(typeof(TopicBasedInterRoleCommunicationTests).FullName));
                    ircExtension.Publish(ev);

                    while (subscriber1.OnNextCount == 0)
                    {
                        Thread.Sleep(ircExtension.Settings.EventWaitTimeout.Add(TimeSpan.FromSeconds(5)));
                    }

                    Assert.IsTrue(retryOccurred, "A retry condition does not seem to have occurred.");
                    Assert.AreEqual<int>(1, subscriber1.OnNextCount);
                }
            }
            finally
            {
                NetworkUtility.EnableNetworkAdapter();
            }
        }
예제 #14
0
        /// <summary>
        /// Publishes the specified inter-role communication event into publish/subscribe messaging infrastructure.
        /// </summary>
        /// <param name="e">The inter-role communication event to be published.</param>
        public void Publish(InterRoleCommunicationEvent e)
        {
            Guard.ArgumentNotNull(e, "e");

            var from = e.From = (this.settings.UseCompetingConsumers ? this.senderRoleID : this.senderInstanceID);
            var to   = String.IsNullOrEmpty(e.To) ? MsgCtxPropValueAny : e.To;

            Func <BrokeredMessage> createMessage = () =>
            {
                var msg = new BrokeredMessage(e, this.serializer);

                // Configure event routing properties.
                msg.Properties[MsgCtxPropNameFrom] = from;
                msg.Properties[MsgCtxPropNameTo]   = to;

                // Configure other message properties and settings.
                msg.TimeToLive = this.settings.EventTimeToLive;

                return(msg);
            };

            // Check if we should perform the send operation asynchronously.
            if (this.settings.EnableAsyncPublish)
            {
                // Declare a BrokeredMessage instance outside the consuming actions so that it can be reused across all 3 delegates below.
                BrokeredMessage msg = null;
#if PERF_TEST
                Stopwatch watch = Stopwatch.StartNew();
#endif
                // Use a retry policy to execute the Send action in an asynchronous and reliable fashion.
                this.retryPolicy.ExecuteAction
                (
                    (cb) =>
                {
                    // A new BrokeredMessage instance must be created each time we send it. Reusing the original BrokeredMessage instance may not work as
                    // the state of its BodyStream cannot be guaranteed to be readable from the beginning.
                    msg = createMessage();

                    // Send the event asynchronously.
                    this.topicClient.BeginSend(msg, cb, null);
                },
                    (ar) =>
                {
                    try
                    {
                        // Complete the asynchronous operation. This may throw an exception that will be handled internally by the retry policy.
                        this.topicClient.EndSend(ar);
#if PERF_TEST
                        watch.Stop();
                        TraceManager.ServiceComponent.TraceDetails("Publishing message into a topic took {0}ms", watch.ElapsedMilliseconds);
#endif
                    }
                    finally
                    {
                        // Ensure that any resources allocated by a BrokeredMessage instance are released.
                        if (msg != null)
                        {
                            msg.Dispose();
                            msg = null;
                        }
                    }
                },
                    (ex) =>
                {
                    // Always dispose the BrokeredMessage instance even if the send operation has completed unsuccessfully.
                    if (msg != null)
                    {
                        msg.Dispose();
                        msg = null;
                    }

                    // Always log exceptions regardless what fault subscribers are doing with the exceptions.
                    TraceManager.ServiceComponent.TraceError(ex);

                    // Notify all registered fault handlers about this exception.
                    foreach (var handler in this.faultHandlers)
                    {
                        try
                        {
                            // Provide the fault observer with exception and original event.
                            handler.Key.OnNext(Tuple.Create <Exception, InterRoleCommunicationEvent>(ex, e));
                        }
                        catch (Exception fault)
                        {
                            // Notify the fault observer that we experienced an error condition.
                            handler.Key.OnError(fault);
                        }
                    }
                }
                );
            }
            else
            {
#if PERF_TEST
                using (TraceManager.ServiceComponent.TraceScope("Publishing message into a topic", e.From, e.To))
#endif
                {
                    // Send the event synchronously, use retry logic to ensure a reliable operation.
                    this.retryPolicy.ExecuteAction(() =>
                    {
                        var msg = createMessage();

                        try
                        {
                            this.topicClient.Send(msg);
                        }
                        finally
                        {
                            // Ensure that any resources allocated by a BrokeredMessage instance are released.
                            if (msg != null)
                            {
                                msg.Dispose();
                            }
                        }
                    });
                }
            }
        }
예제 #15
0
        /// <summary>
        /// Notifies this extension component that it has been registered in the owner's collection of extensions.
        /// </summary>
        /// <param name="owner">The extensible owner object that aggregates this extension.</param>
        public void Attach(IExtensibleCloudServiceComponent owner)
        {
            owner.Extensions.Demand <IRoleConfigurationSettingsExtension>();
            IRoleConfigurationSettingsExtension roleConfigExtension = owner.Extensions.Find <IRoleConfigurationSettingsExtension>();

            this.serviceBusEndpoint = roleConfigExtension.GetServiceBusEndpoint(WellKnownEndpointName.InterRoleCommunication);
            this.retryPolicy        = roleConfigExtension.CommunicationRetryPolicy;

            if (this.serviceBusEndpoint != null)
            {
                // Configure Service Bus credentials and entity URI.
                var credentials = TransportClientCredentialBase.CreateSharedSecretCredential(this.serviceBusEndpoint.IssuerName, this.serviceBusEndpoint.IssuerSecret);
                var address     = ServiceBusEnvironment.CreateServiceUri(WellKnownProtocolScheme.ServiceBus, this.serviceBusEndpoint.ServiceNamespace, String.Empty);

                // Configure Service Bus messaging factory and namespace client which is required for subscription management.
                this.messagingFactory = MessagingFactory.Create(address, credentials);
                this.managementClient = new ServiceBusNamespaceClient(address, credentials);

                ConfigureTopicClient();
                ConfigureSubscriptionClient(this.ircSubscription = ConfigureSubscription(String.Concat(SubscriptionNamePrefix, this.senderInstanceID)));

                // Configure event receive action.
                this.receiveAction = (() =>
                {
                    BrokeredMessage msg = null;

                    this.retryPolicy.ExecuteAction(() =>
                    {
                        // Make sure we are not told to stop receiving while we are retrying.
                        if (!cts.IsCancellationRequested)
                        {
                            if (EventReceiver.TryReceive(Settings.EventWaitTimeout, out msg))
                            {
                                try
                                {
                                    // Make sure we are not told to stop receiving while we were waiting for a new message.
                                    if (!cts.IsCancellationRequested)
                                    {
                                        // Extract the event data from brokered message.
                                        InterRoleCommunicationEvent e = msg.GetBody <InterRoleCommunicationEvent>();

                                        // Notify all registered subscribers.
                                        NotifySubscribers(e);

                                        // Mark brokered message as complete.
                                        msg.Complete(this.retryPolicy);
                                    }
                                    else
                                    {
                                        msg.Defer(this.retryPolicy);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // Abandons a brokered message and unlocks the message.
                                    msg.Abandon(this.retryPolicy);

                                    // Log an error.
                                    TraceManager.ServiceComponent.TraceError(ex);
                                }
                            }
                        }
                    });
                });

                // Configure event receive complete action.
                this.endReceive = ((ar) =>
                {
                    this.receiveAction.EndInvoke(ar);

                    if (!cts.IsCancellationRequested)
                    {
                        this.receiveHandle = this.receiveAction.BeginInvoke(this.endReceive, null);
                    }
                });

                // Configure event send action.
                this.sendAction = ((e) =>
                {
                    this.retryPolicy.ExecuteAction(() => { EventSender.Send(e); });
                });

                // Configure event send complete action.
                this.endSend = ((ar) =>
                {
                    sendAction.EndInvoke(ar);
                });
            }
            else
            {
                throw new CloudApplicationException(String.Format(CultureInfo.CurrentCulture, ExceptionMessages.SpecifiedServiceBusEndpointNotFound, WellKnownEndpointName.InterRoleCommunication, ServiceBusConfigurationSettings.SectionName));
            }
        }
예제 #16
0
        private void HandlePersistenceQueueItem(PersistenceQueueItemInfo itemInfo)
        {
            Guard.ArgumentNotNull(itemInfo, "itemInfo");

            this.owner.Extensions.Demand <IRulesEngineServiceClientExtension>();
            this.owner.Extensions.Demand <IWorkItemSchedulerConfigurationExtension>();
            this.owner.Extensions.Demand <IRoleConfigurationSettingsExtension>();
            this.owner.Extensions.Demand <ICloudStorageProviderExtension>();
            this.owner.Extensions.Demand <IInterRoleCommunicationExtension>();

            IRulesEngineServiceClientExtension       rulesEngineExtension         = this.owner.Extensions.Find <IRulesEngineServiceClientExtension>();
            IWorkItemSchedulerConfigurationExtension configSettingsExtension      = this.owner.Extensions.Find <IWorkItemSchedulerConfigurationExtension>();
            IRoleConfigurationSettingsExtension      roleConfigExtension          = this.owner.Extensions.Find <IRoleConfigurationSettingsExtension>();
            ICloudStorageProviderExtension           storageProviderExtension     = this.owner.Extensions.Find <ICloudStorageProviderExtension>();
            IActivityTrackingEventStreamExtension    trackingEventStreamExtension = this.owner.Extensions.Find <IActivityTrackingEventStreamExtension>();
            IInterRoleCommunicationExtension         interCommExtension           = this.owner.Extensions.Find <IInterRoleCommunicationExtension>();

            // Update BAM activity to indicate when we started the dequeue operation.
            if (trackingEventStreamExtension != null)
            {
                InventoryDataTrackingActivity activity = new InventoryDataTrackingActivity(itemInfo.QueueItemId.ToString())
                {
                    DequeueOperationStarted = DateTime.UtcNow
                };
                trackingEventStreamExtension.UpdateActivity(activity);
            }

            var xPathLib  = roleConfigExtension.GetSection <XPathQueryLibrary>(XPathQueryLibrary.SectionName);
            var batchInfo = rulesEngineExtension.ExecutePolicy <PersistenceQueueItemBatchInfo>(configSettingsExtension.Settings.HandlingPolicyName, itemInfo, new MessageTypeFact(itemInfo.QueueItemType));

            // Verify the batch metadata to ensure we have everything we need to be able to perform de-batching.
            ValidateBatchMetadata(itemInfo, batchInfo);

            // Replace the XPath query references with actual expressions taken from the XPath Library.
            batchInfo.BodyItemXPath      = xPathLib.Queries.Contains(batchInfo.BodyItemXPath) ? xPathLib.GetXPathQuery(batchInfo.BodyItemXPath) : batchInfo.BodyItemXPath;
            batchInfo.BodyItemCountXPath = xPathLib.Queries.Contains(batchInfo.BodyItemCountXPath) ? xPathLib.GetXPathQuery(batchInfo.BodyItemCountXPath) : batchInfo.BodyItemCountXPath;

            var headerXPathList = from item in batchInfo.HeaderSegments where xPathLib.Queries.Contains(item) select new { Segment = item, XPath = xPathLib.GetXPathQuery(item) };
            var bodyXPathList   = from item in batchInfo.BodySegments where xPathLib.Queries.Contains(item) select new { Segment = item, XPath = xPathLib.GetXPathQuery(item) };
            var footerXPathList = from item in batchInfo.FooterSegments where xPathLib.Queries.Contains(item) select new { Segment = item, XPath = xPathLib.GetXPathQuery(item) };

            foreach (var item in headerXPathList.ToList())
            {
                batchInfo.HeaderSegments.Remove(item.Segment);
                batchInfo.HeaderSegments.Add(item.XPath);
            }

            foreach (var item in bodyXPathList.ToList())
            {
                batchInfo.BodySegments.Remove(item.Segment);
                batchInfo.BodySegments.Add(item.XPath);
            }

            foreach (var item in footerXPathList.ToList())
            {
                batchInfo.FooterSegments.Remove(item.Segment);
                batchInfo.FooterSegments.Add(item.XPath);
            }

            int fromItem = 1, toItem = fromItem, maxItems = configSettingsExtension.Settings.XmlBatchSize;
            var taskParameters = new List <DequeueXmlDataTaskState>();

            using (SqlAzurePersistenceQueue persistenceQueue = new SqlAzurePersistenceQueue())
            {
                persistenceQueue.Open(WellKnownDatabaseName.PersistenceQueue);

                using (XmlReader resultReader = persistenceQueue.QueryXmlData(itemInfo.QueueItemId, new string[] { batchInfo.BodyItemCountXPath }, xPathLib.Namespaces.NamespaceManager))
                {
                    maxItems = resultReader.ReadContentAsInt();
                }
            }

            do
            {
                toItem = fromItem + configSettingsExtension.Settings.XmlBatchSize - 1;

                taskParameters.Add(new DequeueXmlDataTaskState()
                {
                    QueueItemInfo      = itemInfo,
                    HeaderSegments     = new List <string>(batchInfo.HeaderSegments),
                    BodySegments       = new List <string>(from query in batchInfo.BodySegments select String.Format(query, fromItem, toItem)),
                    FooterSegments     = new List <string>(batchInfo.FooterSegments),
                    StartItemIndex     = fromItem,
                    EndItemIndex       = toItem,
                    ItemDetectionXPath = batchInfo.BodyItemXPath,
                    Settings           = configSettingsExtension.Settings,
                    StorageProvider    = storageProviderExtension,
                    NamespaceManager   = xPathLib.Namespaces.NamespaceManager
                });

                fromItem += configSettingsExtension.Settings.XmlBatchSize;
            }while (toItem < maxItems);

            // Before we start putting work items on queue, notify the respective queue listeners that they should expect work to arrive.
            CloudQueueWorkDetectedTriggerEvent trigger = new CloudQueueWorkDetectedTriggerEvent(configSettingsExtension.Settings.CloudStorageAccount, configSettingsExtension.Settings.DestinationQueue, maxItems, PayloadSizeKind.MessageCount);

            // Package the trigger into an inter-role communication event.
            var interRoleEvent = new InterRoleCommunicationEvent(trigger);

            // Publish inter-role communication event via the Service Bus one-way multicast.
            interCommExtension.Publish(interRoleEvent);

            var stateCollection = from x in taskParameters.AsParallel <DequeueXmlDataTaskState>()
                                  orderby x.StartItemIndex
                                  select x;

            foreach (var state in stateCollection)
            {
                try
                {
                    DequeueXmlDataTaskMain(state);
                }
                catch (Exception ex)
                {
                    TraceManager.WorkerRoleComponent.TraceError(ex);
                }
            }

            // Update BAM activity to indicate when we completed the dequeue operation.
            if (trackingEventStreamExtension != null)
            {
                InventoryDataTrackingActivity activity = new InventoryDataTrackingActivity(itemInfo.QueueItemId.ToString())
                {
                    DequeueOperationCompleted = DateTime.UtcNow
                };
                trackingEventStreamExtension.UpdateActivity(activity);
            }
        }
예제 #17
0
        /// <summary>
        /// Receives a notification when a new inter-role communication event occurs.
        /// </summary>
        public override void OnNext(TestRunStartEvent msg)
        {
            var numInstances = RoleEnvironment.CurrentRoleInstance.Role.Instances.Count - 1;

            var topicBaseCommunicator = this.interRoleCommunicator as InterRoleCommunicationExtension;

            if (topicBaseCommunicator != null)
            {
                topicBaseCommunicator.Settings.EnableAsyncPublish  = msg.EnableAsyncPublish;
                topicBaseCommunicator.Settings.EnableAsyncDispatch = msg.EnableAsyncDispatch;
            }

            if (msg.RequireTopicCleanup)
            {
                // Delete the IRC topic first so that instances will have enough time to recreate senders and receivers.
                var serviceBusSettings = ConfigurationManager.GetSection(ServiceBusConfigurationSettings.SectionName) as ServiceBusConfigurationSettings;
                var pubsubType         = ConfigurationManager.AppSettings[CommonConsts.ConfigSettingPubSubType];

                if (pubsubType.Equals(CommonConsts.ConfigSettingPubSubTypeValueTopic))
                {
                    var topicEndpoint = serviceBusSettings.Endpoints.Get(CommonConsts.TopicServiceBusEndpointName);
                    var credentials   = TokenProvider.CreateSharedSecretTokenProvider(topicEndpoint.IssuerName, topicEndpoint.IssuerSecret);
                    var address       = ServiceBusEnvironment.CreateServiceUri("sb", topicEndpoint.ServiceNamespace, String.Empty);
                    var nsManager     = new NamespaceManager(address, credentials);

                    if (nsManager.GetTopics().Where(t => String.Compare(t.Path, topicEndpoint.TopicName, true) == 0).Count() > 0)
                    {
                        nsManager.DeleteTopic(topicEndpoint.TopicName);
                    }
                }
            }

            if (msg.PurgeTraceLogTable)
            {
                // Purge WADLogsTable.
                PurgeTraceLogTable();
            }

            // Tell ACK subscriber how many messages it should expect to receive and reset the ACK counter.
            this.ackSubscriber.SetExpectedAckCount(msg.MessageCount * numInstances);
            this.ackSubscriber.ResetAckCounter();

            var testRun = new TestRunTableEntity()
            {
                TestRunID     = msg.TestRunID,
                MessageCount  = msg.MessageCount,
                MessageSize   = msg.MessageSize,
                InstanceCount = numInstances,
                StartDateTime = DateTime.UtcNow,
                EndDateTime   = new DateTime(1900, 1, 1)
            };

            var testRunsTable = new TestRunEntityTableContext(this.tableClient.BaseUri.ToString(), this.tableClient.Credentials);

            testRunsTable.TableName = this.testRunsTableName;

            try
            {
                testRunsTable.AddTestRun(testRun);
            }
            catch (DataServiceRequestException ex)
            {
                if (ex.IsEntityAlreadyExists())
                {
                    testRunsTable.UpdateTestRun(testRun);
                }
            }

            using (TraceManager.WorkerRoleComponent.TraceScope("Publishing IRC events", msg.TestRunID, msg.MessageCount, msg.MessageSize))
            {
                for (int i = 1; i <= msg.MessageCount; i++)
                {
                    DemoPayload payload = new DemoPayload(msg.TestRunID, i, numInstances, DateTime.UtcNow);

                    // Create a data portion of the payload equal to the message size specified in the test run settings.
                    payload.Data = new byte[msg.MessageSize];
                    (new Random()).NextBytes(payload.Data);

                    InterRoleCommunicationEvent ircEvent = new InterRoleCommunicationEvent(payload);

                    // Update publish time so that it accurately reflects the current time.
                    payload.PublishTickCount = HighResolutionTimer.CurrentTickCount;
                    payload.PublishTime      = DateTime.UtcNow;

                    // Publish the IRC event.
                    this.interRoleCommunicator.Publish(ircEvent);
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Initializes a new instance of a <see cref="InterRoleCommunicationExtension"/> object with the specified Service Bus topic endpoint and custom settings.
        /// </summary>
        /// <param name="serviceBusEndpoint">The Service Bus topic endpoint using which this component will be providing inter-role communication.</param>
        /// <param name="settings">The <see cref="InterRoleCommunicationSettings"/> object containing behavioral and runtime settings for the inter-role communication component.</param>
        public InterRoleCommunicationExtension(ServiceBusEndpointInfo serviceBusEndpoint, InterRoleCommunicationSettings settings)
        {
            Guard.ArgumentNotNull(serviceBusEndpoint, "serviceBusEndpoint");
            Guard.ArgumentNotNull(settings, "settings");
            Guard.ArgumentNotNullOrEmptyString(serviceBusEndpoint.TopicName, "serviceBusEndpoint.TopicName");

            // Initialize internal fields.
            this.settings           = settings;
            this.serviceBusEndpoint = serviceBusEndpoint;
            this.retryPolicy        = this.settings.RetryPolicy ?? RetryPolicy.NoRetry;
            this.senderRoleID       = FrameworkUtility.GetHashedValue(CloudEnvironment.DeploymentId, CloudEnvironment.CurrentRoleName);
            this.senderInstanceID   = FrameworkUtility.GetHashedValue(CloudEnvironment.DeploymentId, CloudEnvironment.CurrentRoleInstanceId);

            // Configure Service Bus credentials and service namespace URI.
            var credentials = TokenProvider.CreateSharedSecretTokenProvider(serviceBusEndpoint.IssuerName, serviceBusEndpoint.IssuerSecret);
            var address     = ServiceBusEnvironment.CreateServiceUri("sb", serviceBusEndpoint.ServiceNamespace, String.Empty);

            // Configure Service Bus messaging factory and namespace client which is required for subscription management.
            this.messagingFactory = MessagingFactory.Create(address, credentials);
            this.nsManager        = new NamespaceManager(address, credentials);

            // Figure out the name of the subscription. If subscription name was specified in the endpoint definition, treat it as static.
            // If no subscription name was specified, assign a globally unique name based on hashed deployment ID and role instance ID values.
            this.useStaticSubscription = !String.IsNullOrEmpty(serviceBusEndpoint.SubscriptionName);
            this.ircSubscriptionName   = this.useStaticSubscription ? serviceBusEndpoint.SubscriptionName : (this.settings.UseCompetingConsumers ? String.Concat(SubscriptionNamePrefix, this.senderRoleID) : String.Concat(SubscriptionNamePrefix, this.senderInstanceID));

            // Configure the underlying messaging entities such as topic and subscription.
            ConfigureTopicClient(this.serviceBusEndpoint.TopicName);
            ConfigureSubscriptionClient(this.ircSubscriptionName);

            // Configure a fault handler for the receive action.
            this.receiveFaultAction = ((msg, ex) =>
            {
                // Log an error.
                TraceManager.ServiceComponent.TraceError(ex);

                try
                {
                    if (msg != null)
                    {
                        // Abandons a brokered message. This will cause Service Bus to unlock the message and make it available to be received again,
                        // either by the same consumer or by another completing consumer.
                        msg.Abandon(this.retryPolicy);
                    }
                }
                catch (MessageLockLostException)
                {
                    // It's too late to compensate the loss of a message lock. Should just ignore it so that it does not break the receive loop.
                }
                catch (CommunicationObjectAbortedException)
                {
                    // There is nothing we can do as connection might have been lost or underlying topic/subscription might have been removed.
                }
                catch (CommunicationObjectFaultedException)
                {
                    // If Abandon fail with this exception, the only recourse is to Receive another message (possibly the same one).
                }
            });

            // Configure event receive action.
            this.receiveAction = (() =>
            {
                BrokeredMessage msg = null;
                bool completedAsync = false;

                this.retryPolicy.ExecuteAction(() =>
                {
                    // Make sure we are not told to stop receiving while we are retrying.
                    if (!cts.IsCancellationRequested)
                    {
#if PERF_TEST
                        Stopwatch watch = Stopwatch.StartNew();
#endif
                        if ((msg = this.subscriptionClient.Receive(this.settings.EventWaitTimeout)) != null)
                        {
#if PERF_TEST
                            watch.Stop();
                            TraceManager.ServiceComponent.TraceDetails("Waited for a new event for {0}ms", watch.ElapsedMilliseconds);
#endif
                            try
                            {
                                // Make sure we are not told to stop receiving while we were waiting for a new message.
                                if (!this.cts.IsCancellationRequested)
                                {
                                    if (this.settings.EnableAsyncDispatch)
                                    {
                                        // Invoke the dispatch action asynchronously.
                                        this.dispatchAction.BeginInvoke(msg, this.endDispatch, msg);

                                        completedAsync = true;
                                    }
                                    else
                                    {
                                        // Invoke the dispatch action synchronously.
                                        this.dispatchAction(msg);

                                        // Mark brokered message as complete.
                                        msg.Complete(this.retryPolicy);
                                    }
                                }
                                else
                                {
                                    // If we were told to stop processing, the current message needs to be unlocked and return back to the queue.
                                    msg.Abandon(this.retryPolicy);
                                }
                            }
                            catch (Exception ex)
                            {
                                this.receiveFaultAction(msg, ex);
                            }
                            finally
                            {
                                // Do not attempt to dispose a BrokeredMessage instance if it was dispatched for processing asynchronously.
                                if (msg != null && !completedAsync)
                                {
                                    // Ensure that any resources allocated by a BrokeredMessage instance are released.
                                    msg.Dispose();
                                }
                            }
                        }
                    }
                });
            });

            // Configure event receive complete action.
            this.endReceive = ((ar) =>
            {
                try
                {
                    this.receiveAction.EndInvoke(ar);
                }
                catch (Exception ex)
                {
                    // Log this error. Do not allow an unhandled exception to kill the current process.
                    TraceManager.ServiceComponent.TraceError(ex);
                }

                if (!cts.IsCancellationRequested)
                {
                    this.receiveHandle = this.receiveAction.BeginInvoke(this.endReceive, null);
                }
            });

            // Configure event dispatch action. This action is performed when notifying subscribers about a new IRC event.
            this.dispatchAction = ((msg) =>
            {
                // Extract the event data from brokered message.
                InterRoleCommunicationEvent e = msg.GetBody <InterRoleCommunicationEvent>(this.serializer);

                // Notify all registered subscribers.
                NotifySubscribers(e);
            });

            this.endDispatch = ((ar) =>
            {
                BrokeredMessage msg = null;

                try
                {
                    msg = ar.AsyncState as BrokeredMessage;
                    this.dispatchAction.EndInvoke(ar);

                    if (msg != null)
                    {
                        // Mark brokered message as complete.
                        msg.Complete(this.retryPolicy);
                    }
                }
                catch (Exception ex)
                {
                    this.receiveFaultAction(msg, ex);
                }
                finally
                {
                    if (msg != null)
                    {
                        // Ensure that any resources allocated by a BrokeredMessage instance are released.
                        msg.Dispose();
                    }
                }
            });
        }