/// <summary> /// Creates a new instance of the inter-role communication event with the specified payload and deployment ID, role name and role instance ID that identify the recipient. /// </summary> /// <param name="payload">The event payload.</param> /// <param name="deploymentID">The deployment ID identifying a hosted service in which the recipients for the inter-role communication event are deployed.</param> /// <param name="roleName">The name identifying a role to which inter-role communication event recipient belong.</param> /// <param name="roleInstanceID">The role instance ID uniquely identifying a particular recipient of the inter-role communication event.</param> public InterRoleCommunicationEvent(object payload, string deploymentID = null, string roleName = null, string roleInstanceID = null) : this(payload) { // Check of role instance ID was specified. if (!String.IsNullOrEmpty(roleInstanceID)) { // If role instance ID is specified, use a combination of deployment ID and role instance ID to determine where to send. To = FrameworkUtility.GetHashedValue(deploymentID ?? CloudEnvironment.DeploymentId, roleInstanceID); } else if (!String.IsNullOrEmpty(roleName)) { // If role instance ID is not provided but name was specified instead, assume that the event is to be sent to all instances of a particular role. To = FrameworkUtility.GetHashedValue(deploymentID ?? CloudEnvironment.DeploymentId, roleName); } // Otherwise, treat this event as a multicast event and do not set the To property. }
/// <summary> /// Initializes a new instance of the <see cref="InterRoleCommunicationExtension"/> object with default settings. /// </summary> public InterRoleCommunicationExtension() { // Initialize internal fields. this.settings = InterRoleCommunicationSettings.Default; this.senderInstanceID = FrameworkUtility.GetHashedValue(CloudEnvironment.DeploymentId, CloudEnvironment.CurrentRoleInstanceId); }
/// <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(); } } }); }
/// <summary> /// Creates a new instance of the multicast inter-role communication event with the specified payload. /// </summary> /// <param name="payload">The event payload.</param> public InterRoleCommunicationEvent(object payload) { From = FrameworkUtility.GetHashedValue(CloudEnvironment.DeploymentId, CloudEnvironment.CurrentRoleInstanceId); Properties = new Dictionary <string, object>(); Payload = payload; }
/// <summary> /// Constructs and returns a queue name that is unique for the specified instance ID and is safe to be used as a name for the Windows Azure Service Bus Message Buffer. /// </summary> /// <param name="instanceId">A string that uniquely and reliably identifies the process in which the OnPremisesBufferedTraceListener trace listener is running.</param> /// <returns>The constructed queue name.</returns> private static string GetServiceBusQueueName(string instanceId) { Guard.ArgumentNotNullOrEmptyString(instanceId, "instanceId"); return(CloudUtility.CleanupContainerName(String.Concat(Resources.OnPremisesBufferedTraceListenerQueueName, "-", FrameworkUtility.GetHashedValue(instanceId)).ToLowerInvariant())); }