/// <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); } }
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; } }
/// <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); } } }
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); } }
/// <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); }
/// <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); }
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); } } } }
/// <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(); } }
/// <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(); } } }); } } }
/// <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)); } }
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); } }
/// <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); } } }
/// <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(); } } }); }