/// <summary> /// Initializes a new instance of the BrokerController class /// </summary> /// <param name="isSingleton">indicating whether the BrokerController is a singleton</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="observer">indicating broker observer</param> /// <param name="azureQueueProxy">the Azure storage proxy</param> public BrokerController(bool isSingleton, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BrokerObserver observer, AzureQueueProxy azureQueueProxy) { this.isSingleton = isSingleton; this.clientManager = clientManager; this.brokerAuth = brokerAuth; this.observer = observer; this.callbackInstance = azureQueueProxy; }
/// <summary> /// Initializes a new instance of the ControllerFrontendProvider class /// </summary> /// <param name="isSingleton">indicating whether a singleton controller class is required</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="observer">indicating broker observer</param> /// <param name="azureQueueProxy">indicating the Azure storage proxy</param> public ControllerFrontendProvider(bool isSingleton, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BrokerObserver observer, AzureQueueProxy azureQueueProxy) { if (isSingleton && azureQueueProxy != null) { this.singletonInstance = new BrokerController(true, clientManager, brokerAuth, observer, azureQueueProxy); this.cloudQueueWatcher = new BrokerWorkerControllerQueueWatcher(this.singletonInstance, azureQueueProxy.AzureStorageConnectionString, azureQueueProxy.SessionId); } this.clientManager = clientManager; this.brokerAuth = brokerAuth; this.observer = observer; this.azureQueueProxy = azureQueueProxy; }
/// <summary> /// Initializes a new instance of the BrokerInfo class from broker recover info /// </summary> /// <param name="recoverInfo">indicating the broker recover info</param> /// <param name="brokerInfo">indicating the broker start info</param> /// <param name="auth">indicating the broker auth</param> /// <param name="customBroker">indicating the custom broker configuration</param> /// <param name="pool">indicating the broker process pool</param> public BrokerInfo(BrokerRecoverInfo recoverInfo, BrokerStartInfo brokerInfo, BrokerAuthorization auth, CustomBrokerRegistration customBroker, BrokerProcessPool pool) { this.callbackToCloseBroker = new ThreadHelper <IAsyncResult>(new AsyncCallback(this.OnCloseBroker)).CallbackRoot; this.durable = recoverInfo.Durable; this.brokerInfo = brokerInfo; this.sessionId = recoverInfo.SessionId; this.sessionStartInfo = recoverInfo.StartInfo; this.auth = auth; this.customBroker = customBroker; this.pool = pool; this.sessionStartInfo.IpAddress = BrokerLauncherSettings.Default.SvcHostList.Cast <string>().ToArray(); this.sessionStartInfo.RegPath = BrokerLauncherSettings.Default.CCP_SERVICEREGISTRATION_PATH; }
/// <summary> /// Initializes a new instance of the FrontEndBase class /// </summary> /// <param name="listenUri">indicate the listen uri</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="sharedData">indicating the shared data</param> public FrontEndBase(string listenUri, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, SharedData sharedData) { this.replySentCallback = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.ReplySent, this).CallbackRoot; this.tryToReceiveRequestCallback = new BasicCallbackReferencedThreadHelper <object>(this.TryToReceiveRequestCallback, this).CallbackRoot; this.listenUri = listenUri; this.throttlingWaitHandle = new ManualResetEvent(false); this.callbackStateQueue = new Queue <ChannelClientState>(); this.callbackStateQueueLock = new object(); this.observer = observer; this.clientManager = clientManager; this.brokerAuth = brokerAuth; this.sharedData = sharedData; this.observer.OnStartThrottling += this.StartThrottling; this.observer.OnStopThrottling += this.StopThrottling; }
/// <summary> /// Build the frontend /// </summary> /// <param name="sharedData">indicating the shared data</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="bindings">indicating the bindings</param> /// <param name="azureQueueProxy">indicating the Azure storage proxy</param> /// <returns>frontend result</returns> public static FrontendResult BuildFrontEnd(SharedData sharedData, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BindingsSection bindings, AzureQueueProxy azureQueueProxy) { FrontendResult result = new FrontendResult(); // Bug 9514: Do not open frontend for inprocess broker if (sharedData.StartInfo.UseInprocessBroker) { return(result); } bool flag = false; // Open frontend for different scheme // TODO: Separate HTTP frontend and Queue frontend if (azureQueueProxy != null) { flag = true; result.SetFrontendInfo(BuildHttpFrontend(sharedData, observer, clientManager, brokerAuth, bindings, azureQueueProxy), TransportScheme.Http); } else { if ((sharedData.StartInfo.TransportScheme & TransportScheme.Custom) == TransportScheme.Custom) { flag = true; result.SetFrontendInfo(BuildCustomFrontend(sharedData, observer, clientManager, brokerAuth, bindings), TransportScheme.Custom); } if ((sharedData.StartInfo.TransportScheme & TransportScheme.Http) == TransportScheme.Http) { flag = true; result.SetFrontendInfo(BuildHttpFrontend(sharedData, observer, clientManager, brokerAuth, bindings, azureQueueProxy), TransportScheme.Http); } if ((sharedData.StartInfo.TransportScheme & TransportScheme.NetTcp) == TransportScheme.NetTcp) { flag = true; result.SetFrontendInfo(BuildNetTcpFrontend(sharedData, observer, clientManager, brokerAuth, bindings), TransportScheme.NetTcp); } if ((sharedData.StartInfo.TransportScheme & TransportScheme.NetHttp) == TransportScheme.NetHttp) { flag = true; result.SetFrontendInfo(BuildNetHttpFrontend(sharedData, observer, clientManager, brokerAuth, bindings), TransportScheme.NetHttp); } } if (!flag) { BrokerTracing.TraceEvent(TraceEventType.Critical, 0, "[FrontEndBuilder] Invalid transport scheme: {0}", sharedData.StartInfo.TransportScheme); ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_NotSupportedTransportScheme, SR.NotSupportedTransportScheme, sharedData.StartInfo.TransportScheme.ToString()); } return(result); }
/// <summary> /// Build the custom frontend /// </summary> /// <param name="sharedData">indicating the shared data</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="bindings">indicating the bindings</param> /// <returns>frontend info</returns> private static FrontendInfo BuildCustomFrontend(SharedData sharedData, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BindingsSection bindings) { FrontendInfo result = new FrontendInfo(); BrokerTracing.TraceVerbose("[FrontEndBuilder] Start building custom frontend..."); // Get binding from configuration file Binding binding = BindingHelper.GetBinding(TransportScheme.Custom, sharedData.StartInfo.Secure, bindings); // Get message size and reader quotas BindingElementCollection collection = binding.CreateBindingElements(); // Sync frontend binding.receiveTimeout with loadBalancing.ServiceOperationTimeout if its enabled (>0) int serviceOperationTimeout = sharedData.Config.LoadBalancing.ServiceOperationTimeout; if (serviceOperationTimeout > 0) { binding.SendTimeout = TimeSpan.FromMilliseconds(serviceOperationTimeout); } // Set frontend binding.ReceiveTimeout to max binding.ReceiveTimeout = TimeSpan.MaxValue; TransportBindingElement transportBindingElement = collection.Find <TransportBindingElement>(); XmlDictionaryReaderQuotas quotas = binding.GetProperty <XmlDictionaryReaderQuotas>(new BindingParameterCollection()); if (sharedData.ServiceConfig.MaxMessageSize > 0) { transportBindingElement.MaxReceivedMessageSize = sharedData.Config.LoadBalancing.ServiceOperationTimeout; quotas.MaxBytesPerRead = XmlDictionaryReaderQuotas.Max.MaxBytesPerRead; quotas.MaxDepth = XmlDictionaryReaderQuotas.Max.MaxDepth; quotas.MaxNameTableCharCount = XmlDictionaryReaderQuotas.Max.MaxNameTableCharCount; quotas.MaxStringContentLength = Convert.ToInt32(sharedData.ServiceConfig.MaxMessageSize); quotas.MaxArrayLength = Convert.ToInt32(sharedData.ServiceConfig.MaxMessageSize); } result.MaxMessageSize = transportBindingElement.MaxReceivedMessageSize; result.ReaderQuotas = quotas; // Check if the custom binding supports duplex binding bool duplex = false; if (binding.CanBuildChannelListener <IDuplexSessionChannel>()) { duplex = true; } StringBuilder sb = new StringBuilder(); BrokerTracing.WriteProperties(sb, result.ReaderQuotas, 3, typeof(int)); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 1: Load binding data:\nMaxMessageSize = {0}\n[ReaderQuotas]\n{1}\nDuplex = {2}", result.MaxMessageSize, sb.ToString(), duplex); result.Binding = binding; BrokerTracing.EtwTrace.LogFrontendBindingLoaded( sharedData.BrokerInfo.SessionId, "Custom", result.MaxMessageSize, binding.ReceiveTimeout.Ticks, binding.SendTimeout.Ticks, binding.MessageVersion.ToString(), binding.Scheme); // Generate the net.tcp uri Uri baseUri = sharedData.Config.Services.GetBrokerBaseAddress(binding.Scheme); if (baseUri == null) { baseUri = GetDefaultUriByScheme(binding.Scheme); } BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 2: Load base address: {0}", baseUri); Uri brokerUri = ApplySessionId(baseUri, sharedData.BrokerInfo.SessionId, "Custom", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 3: Generate broker uri: {0}", brokerUri); // Build the frontend if (duplex) { result.FrontEnd = new DuplexFrontEnd(brokerUri, binding, observer, clientManager, brokerAuth, sharedData); } else { if (binding.CanBuildChannelListener <IReplySessionChannel>()) { result.FrontEnd = new RequestReplyFrontEnd <IReplySessionChannel>(brokerUri, binding, observer, clientManager, brokerAuth, sharedData); } else if (binding.CanBuildChannelListener <IReplyChannel>()) { result.FrontEnd = new RequestReplyFrontEnd <IReplyChannel>(brokerUri, binding, observer, clientManager, brokerAuth, sharedData); } else { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_BindingNotSupported, SR.BindingNotSupported, binding.Name); } } BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 4: Build broker frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendCreated( sharedData.BrokerInfo.SessionId, "Custom", result.FrontEnd.ListenUri); Uri controllerUri = ApplySessionId(baseUri, sharedData.BrokerInfo.SessionId, "Custom", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 5: Generate controller base address: {0}", controllerUri); result.ControllerFrontend = new ServiceHost(typeof(BrokerController), controllerUri); BindingHelper.ApplyDefaultThrottlingBehavior(result.ControllerFrontend); ServiceEndpoint controllerEndpoint = result.ControllerFrontend.AddServiceEndpoint(typeof(IController), binding, DefaultControllerPostfix); controllerEndpoint.Behaviors.Add(new ControllerFrontendProvider(false, clientManager, brokerAuth, observer, null)); result.ControllerUri = controllerEndpoint.ListenUri.AbsoluteUri; // Check if the binding supports duplex channel // If so, create GetResponse frontend if (binding.CanBuildChannelListener <IDuplexChannel>() || binding.CanBuildChannelListener <IDuplexSessionChannel>()) { ServiceEndpoint getResponseEndpoint = result.ControllerFrontend.AddServiceEndpoint(typeof(IResponseService), binding, DefaultGetResponsePostfix); getResponseEndpoint.Behaviors.Add(new ControllerFrontendProvider(false, clientManager, brokerAuth, observer, null)); result.GetResponseUri = getResponseEndpoint.ListenUri.AbsoluteUri; BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 6: Build controller frontend succeeded: ControllerUri = {0}, GetResponseUri = {1}", result.ControllerUri, result.GetResponseUri); } else { BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 6: Build controller frontend succeeded: ControllerUri = {0}", result.ControllerUri); } BrokerTracing.TraceVerbose("[FrontEndBuilder] Building custom frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendControllerCreated( sharedData.BrokerInfo.SessionId, "Custom", result.ControllerUri, result.GetResponseUri ?? String.Empty); return(result); }
/// <summary> /// Build the http frontend /// </summary> /// <param name="sharedData">indicating the shared data</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="bindings">indicating the bindings</param> /// <returns>frontend info</returns> private static FrontendInfo BuildHttpFrontend(SharedData sharedData, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BindingsSection bindings, AzureQueueProxy azureQueueProxy) { FrontendInfo result = new FrontendInfo(); BrokerTracing.TraceVerbose("[FrontEndBuilder] Start building http frontend..."); // Get binding from configuration file Binding binding = BindingHelper.GetBinding(TransportScheme.Http, sharedData.StartInfo.Secure, bindings); // Sync frontend binding.receiveTimeout with loadBalancing.ServiceOperationTimeout if its enabled (>0) int serviceOperationTimeout = sharedData.Config.LoadBalancing.ServiceOperationTimeout; if (serviceOperationTimeout > 0) { binding.SendTimeout = TimeSpan.FromMilliseconds(serviceOperationTimeout); } // Set frontend binding.ReceiveTimeout to max binding.ReceiveTimeout = TimeSpan.MaxValue; // Get message size and reader quotas int maxMessageSize = sharedData.ServiceConfig.MaxMessageSize; if (maxMessageSize > 0) { BindingHelper.ApplyMaxMessageSize(binding, maxMessageSize); result.MaxMessageSize = maxMessageSize; BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 1: Apply global MaxMessageSize:{0}\n", result.MaxMessageSize); } else { BindingElementCollection collection = binding.CreateBindingElements(); result.MaxMessageSize = collection.Find <TransportBindingElement>().MaxReceivedMessageSize; result.ReaderQuotas = binding.GetProperty <XmlDictionaryReaderQuotas>(new BindingParameterCollection()); StringBuilder sb = new StringBuilder(); BrokerTracing.WriteProperties(sb, result.ReaderQuotas, 3, typeof(int)); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 1: Load binding data:\nMaxMessageSize = {0}\n[ReaderQuotas]\n{1}", result.MaxMessageSize, sb.ToString()); } result.Binding = binding; BrokerTracing.EtwTrace.LogFrontendBindingLoaded( sharedData.BrokerInfo.SessionId, "Http", result.MaxMessageSize, binding.ReceiveTimeout.Ticks, binding.SendTimeout.Ticks, binding.MessageVersion.ToString(), binding.Scheme); // Generate the http uri Uri basehttpUri = sharedData.Config.Services.GetBrokerBaseAddress(sharedData.StartInfo.Secure ? HttpsScheme : HttpScheme); if (basehttpUri == null) { basehttpUri = new Uri(sharedData.StartInfo.Secure ? DefaultHttpsFrontEndServiceUri : DefaultHttpFrontEndServiceUri); } BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 2: Load base address: {0}", basehttpUri); Uri brokerHttpUri = ApplySessionId(basehttpUri, sharedData.BrokerInfo.SessionId, "Http", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 3: Generate broker uri: {0}", brokerHttpUri); // Build the frontend if (sharedData.StartInfo.UseAzureStorage == true) { BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: AzureQueueFrontEnd"); result.FrontEnd = new AzureQueueFrontEnd(azureQueueProxy, brokerHttpUri, observer, clientManager, brokerAuth, sharedData); } else { BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: HttpFrontEnd"); result.FrontEnd = new RequestReplyFrontEnd <IReplyChannel>(brokerHttpUri, binding, observer, clientManager, brokerAuth, sharedData); //result.FrontEnd = new OutputInputFrontEnd<IInputChannel>(brokerHttpUri, binding, observer, clientManager, brokerAuth, sharedData); } BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 4: Build broker frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendCreated( sharedData.BrokerInfo.SessionId, "Http", result.FrontEnd.ListenUri); Uri controllerHttpUri = ApplySessionId(basehttpUri, sharedData.BrokerInfo.SessionId, "Http", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 5: Generate controller base address: {0}", controllerHttpUri); // Bug 3012: Force the http frontend using the singleton instance result.ControllerFrontend = new ServiceHost(typeof(BrokerController), controllerHttpUri); BindingHelper.ApplyDefaultThrottlingBehavior(result.ControllerFrontend); ServiceBehaviorAttribute behavior = result.ControllerFrontend.Description.Behaviors.Find <ServiceBehaviorAttribute>(); Debug.Assert(behavior != null, "BrokerController must have a behavior."); behavior.InstanceContextMode = InstanceContextMode.Single; ServiceEndpoint endpoint = result.ControllerFrontend.AddServiceEndpoint(typeof(IController), binding, DefaultControllerPostfix); if (sharedData.StartInfo.UseAzureStorage == true) { endpoint.Behaviors.Add(new ControllerFrontendProvider(true, clientManager, brokerAuth, observer, azureQueueProxy)); } else { endpoint.Behaviors.Add(new ControllerFrontendProvider(true, clientManager, brokerAuth, observer, null)); } result.ControllerUri = endpoint.ListenUri.AbsoluteUri; BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 6: Build controller frontend succeeded: ControllerUri = {0}", result.ControllerUri); result.GetResponseUri = null; BrokerTracing.TraceVerbose("[FrontEndBuilder] Building http frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendControllerCreated( sharedData.BrokerInfo.SessionId, "Http", result.ControllerUri, String.Empty); return(result); }
/// <summary> /// Build the NetHttp frontend /// </summary> /// <param name="sharedData">indicating the shared data</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="bindings">indicating the bindings</param> /// <returns>frontend info</returns> private static FrontendInfo BuildNetHttpFrontend(SharedData sharedData, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, BindingsSection bindings) { FrontendInfo result = new FrontendInfo(); BrokerTracing.TraceVerbose("[FrontEndBuilder] Start building NetHttp frontend..."); // Get binding from configuration file Binding binding = BindingHelper.GetBinding(TransportScheme.NetHttp, sharedData.StartInfo.Secure, bindings); // Sync frontend binding.receiveTimeout with loadBalancing.ServiceOperationTimeout if its enabled (>0) int serviceOperationTimeout = sharedData.Config.LoadBalancing.ServiceOperationTimeout; if (serviceOperationTimeout > 0) { binding.SendTimeout = TimeSpan.FromMilliseconds(serviceOperationTimeout); } // Set frontend binding.ReceiveTimeout to max binding.ReceiveTimeout = TimeSpan.MaxValue; // Update backend binding's maxMessageSize settings with global maxMessageSize if its enabled (> 0) int maxMessageSize = sharedData.ServiceConfig.MaxMessageSize; if (maxMessageSize > 0) { BindingHelper.ApplyMaxMessageSize(binding, maxMessageSize); result.MaxMessageSize = maxMessageSize; BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 1: Apply global MaxMessageSize:{0}\n", result.MaxMessageSize); } else { // Get message size and reader quotas BindingElementCollection collection = binding.CreateBindingElements(); result.MaxMessageSize = collection.Find <TransportBindingElement>().MaxReceivedMessageSize; result.ReaderQuotas = binding.GetProperty <XmlDictionaryReaderQuotas>(new BindingParameterCollection()); StringBuilder sb = new StringBuilder(); BrokerTracing.WriteProperties(sb, result.ReaderQuotas, 3, typeof(int)); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 1: Load binding data:\nMaxMessageSize = {0}\n[ReaderQuotas]\n{1}", result.MaxMessageSize, sb.ToString()); } result.Binding = binding; BrokerTracing.EtwTrace.LogFrontendBindingLoaded( sharedData.BrokerInfo.SessionId, "NetHttp", result.MaxMessageSize, binding.ReceiveTimeout.Ticks, binding.SendTimeout.Ticks, binding.MessageVersion.ToString(), binding.Scheme); // Generate the http uri Uri basehttpUri = sharedData.Config.Services.GetBrokerBaseAddress(sharedData.StartInfo.Secure ? HttpsScheme : HttpScheme); if (basehttpUri == null) { basehttpUri = new Uri(sharedData.StartInfo.Secure ? DefaultHttpsFrontEndServiceUri : DefaultHttpFrontEndServiceUri); } BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 2: Load base address: {0}", basehttpUri); Uri brokerNetHttpUri = ApplySessionId(basehttpUri, sharedData.BrokerInfo.SessionId, "NetHttp", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 3: Generate broker uri: {0}", brokerNetHttpUri); // Build the frontend result.FrontEnd = new DuplexFrontEnd(brokerNetHttpUri, binding, observer, clientManager, brokerAuth, sharedData); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 4: Build broker frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendCreated( sharedData.BrokerInfo.SessionId, "NetHttp", result.FrontEnd.ListenUri); Uri controllerNetHttpUri = ApplySessionId(basehttpUri, sharedData.BrokerInfo.SessionId, "NetHttp", sharedData.BrokerInfo.EnableFQDN); BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 5: Generate controller base address: {0}", controllerNetHttpUri); result.ControllerFrontend = new ServiceHost(typeof(BrokerController), controllerNetHttpUri); BindingHelper.ApplyDefaultThrottlingBehavior(result.ControllerFrontend); ServiceEndpoint controllerEndpoint = result.ControllerFrontend.AddServiceEndpoint(typeof(IController), binding, DefaultControllerPostfix); controllerEndpoint.Behaviors.Add(new ControllerFrontendProvider(false, clientManager, brokerAuth, observer, null)); result.ControllerUri = controllerEndpoint.ListenUri.AbsoluteUri; ServiceEndpoint getResponseEndpoint = result.ControllerFrontend.AddServiceEndpoint(typeof(IResponseService), binding, DefaultGetResponsePostfix); getResponseEndpoint.Behaviors.Add(new ControllerFrontendProvider(false, clientManager, brokerAuth, observer, null)); result.GetResponseUri = getResponseEndpoint.ListenUri.AbsoluteUri; BrokerTracing.TraceVerbose("[FrontEndBuilder] Build frontend: Step 6: Build controller frontend succeeded: ControllerUri = {0}, GetResponseUri = {1}", result.ControllerUri, result.GetResponseUri); BrokerTracing.TraceVerbose("[FrontEndBuilder] Building NetHttp frontend succeeded."); BrokerTracing.EtwTrace.LogFrontendControllerCreated( sharedData.BrokerInfo.SessionId, "NetHttp", result.ControllerUri, result.GetResponseUri); return(result); }
/// <summary> /// Create a broker appdomain /// </summary> /// <param name="recoverInfo">broker recover info</param> /// <param name="sessionid">session id</param> /// <param name="durable">indicate if the session is durable</param> /// <param name="attached">indicate if it is attaching</param> /// <returns>returns the initialization result</returns> private async Task <BrokerInitializationResult> CreateBrokerAndRun(BrokerRecoverInfo recoverInfo, bool attached, ClusterInfoContract clusterInfo) { // Check the brokerDic to see if the session Id already exists lock (this.brokerDic) { if (this.brokerDic.ContainsKey(recoverInfo.SessionId)) { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_SessionIdAlreadyExists, SR.SessionIdAlreadyExists, recoverInfo.SessionId.ToString()); } if (BrokerLauncherSettings.Default.MaxConcurrentSession > 0 && this.brokerDic.Count >= BrokerLauncherSettings.Default.MaxConcurrentSession) { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_TooManyBrokerRunning, SR.TooManyBrokerRunning, BrokerLauncherSettings.Default.MaxConcurrentSession.ToString()); } } //TODO: SF: make sure the clusterInfo.NetworkTopology string can be converted to ClusterTopology enum //ClusterTopology topo = ClusterTopology.Public; // ClusterTopology topo; // Enum.TryParse<ClusterTopology>(clusterInfo.NetworkTopology, out topo); //get soa configurations Dictionary <string, string> soaConfig = new Dictionary <string, string>(); List <string> keys = new List <string>() { Constant.RegistryPathEnv, Constant.AutomaticShrinkEnabled, Constant.NettcpOver443, Constant.NetworkPrefixEnv, Constant.EnableFqdnEnv }; soaConfig = await this.schedulerHelper.GetSOAConfigurations(keys); ServiceRegistrationRepo serviceRegistration = await this.GetRegistrationRepo(soaConfig[Constant.RegistryPathEnv]); string serviceRegistrationPath = serviceRegistration.GetServiceRegistrationPath(recoverInfo.StartInfo.ServiceName, recoverInfo.StartInfo.ServiceVersion); if (serviceRegistrationPath == null) { throw new FileNotFoundException("Registration file is not found", recoverInfo.StartInfo.ServiceName); } CustomBrokerRegistration customBroker = GetCustomBroker(serviceRegistrationPath); // Build the broker start info BrokerStartInfo brokerInfo = new BrokerStartInfo(); brokerInfo.SessionId = recoverInfo.SessionId; #if HPCPACK brokerInfo.JobOwnerSID = await this.schedulerHelper.GetJobOwnerSID(brokerInfo.SessionId); #endif brokerInfo.Durable = recoverInfo.Durable; brokerInfo.Attached = attached; //this is scheduler node or cluster connection string brokerInfo.Headnode = this.headnode; brokerInfo.PurgedFailed = recoverInfo.PurgedFailed; brokerInfo.PurgedProcessed = recoverInfo.PurgedProcessed; brokerInfo.PurgedTotal = recoverInfo.PurgedTotal; brokerInfo.ConfigurationFile = serviceRegistrationPath; brokerInfo.NetworkTopology = 0; // ClusterTopology.Public brokerInfo.ClusterName = clusterInfo.ClusterName; brokerInfo.ClusterId = clusterInfo.ClusterId; brokerInfo.AzureStorageConnectionString = clusterInfo.AzureStorageConnectionString; brokerInfo.Standalone = BrokerLauncherEnvironment.Standalone; brokerInfo.UseAad = recoverInfo.StartInfo.UseAad; brokerInfo.AadUserSid = recoverInfo.AadUserSid; brokerInfo.AadUserName = recoverInfo.AadUserName; if (soaConfig.TryGetValue(Constant.AutomaticShrinkEnabled, out var v)) { brokerInfo.AutomaticShrinkEnabled = Convert.ToBoolean(v); } else { brokerInfo.AutomaticShrinkEnabled = false; } if (SoaHelper.IsOnAzure()) { brokerInfo.EnableDiagTrace = true; } else { brokerInfo.EnableDiagTrace = SoaDiagTraceHelper.IsDiagTraceEnabled(recoverInfo.SessionId); } if (!SoaHelper.IsSchedulerOnAzure()) { // default value is true bool nettcpOver443 = true; string value = soaConfig[Constant.NettcpOver443]; if (!string.IsNullOrEmpty(value)) { if (!bool.TryParse(value, out nettcpOver443)) { nettcpOver443 = true; } } brokerInfo.HttpsBurst = !nettcpOver443; } if (SoaHelper.IsSchedulerOnAzure()) { // do not need network prefix for the Azure nodes brokerInfo.NetworkPrefix = string.Empty; } else { brokerInfo.NetworkPrefix = soaConfig[Constant.NetworkPrefixEnv]; } // get enableFQDN setting from the cluster env var bool enableFQDN = false; string enableFqdnStr = soaConfig[Constant.EnableFqdnEnv]; if (!string.IsNullOrEmpty(enableFqdnStr)) { if (bool.TryParse(enableFqdnStr, out enableFQDN)) { brokerInfo.EnableFQDN = enableFQDN; BrokerTracing.TraceVerbose( "[BrokerManager].CreateBrokerAndRun: The enableFQDN setting in cluster env var is {0}", enableFQDN); } else { BrokerTracing.TraceError( "[BrokerManager].CreateBrokerAndRun: The enableFQDN setting \"{0}\" in cluster env var is not a valid bool value.", enableFqdnStr); } } // set persist version. if (!brokerInfo.Attached) { //if creating a new session, set persist version to BrokerVersion.PersistVersion brokerInfo.PersistVersion = BrokerVersion.PersistVersion; } else { //if attaching an existing session, get PersistVersion from recoverInfo if (recoverInfo.PersistVersion.HasValue) { brokerInfo.PersistVersion = recoverInfo.PersistVersion.Value; } else { // if recover info doesn't have PersistVersion info, default to DefaultPersistVersion brokerInfo.PersistVersion = BrokerVersion.DefaultPersistVersion; } // if version is not supported, throw UnsupportedVersion exception if (!BrokerVersion.IsSupportedPersistVersion(brokerInfo.PersistVersion)) { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_UnsupportedVersion, SR.UnsupportedVersion, brokerInfo.PersistVersion.ToString(), BrokerVersion.PersistVersion.ToString()); } } BrokerAuthorization auth = null; if (recoverInfo.StartInfo.Secure) { if (recoverInfo.StartInfo.ShareSession) { #if HPCPACK brokerInfo.JobTemplateACL = await this.schedulerHelper.GetJobTemplateACL(recoverInfo.StartInfo.JobTemplate); auth = new BrokerAuthorization(brokerInfo.JobTemplateACL, (int)JobTemplateRights.SubmitJob, (int)JobTemplateRights.Generic_Read, (int)JobTemplateRights.Generic_Write, (int)JobTemplateRights.Generic_Execute, (int)JobTemplateRights.Generic_All); #endif // TODO: support share session throw new NotImplementedException(); } else { auth = new BrokerAuthorization(new SecurityIdentifier(brokerInfo.JobOwnerSID)); } } BrokerInfo info = new BrokerInfo(recoverInfo, brokerInfo, auth, customBroker, this.pool); try { info.BrokerExited += new EventHandler(this.BrokerInfo_BrokerExited); // if the broker exit quickly due to short timeouts, the broker info could remain in the brokerDic, because it is added later. info.StartBroker(); lock (this.brokerDic) { if (BrokerLauncherSettings.Default.MaxConcurrentSession > 0 && this.brokerDic.Count >= BrokerLauncherSettings.Default.MaxConcurrentSession) { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_TooManyBrokerRunning, SR.TooManyBrokerRunning, BrokerLauncherSettings.Default.MaxConcurrentSession.ToString()); } if (this.brokerDic.ContainsKey(recoverInfo.SessionId)) { ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_SessionIdAlreadyExists, SR.SessionIdAlreadyExists, recoverInfo.SessionId.ToString()); } this.brokerDic.Add(recoverInfo.SessionId, info); } // Update broker info into job property await this.schedulerHelper.UpdateBrokerInfo(info); } catch (Exception e) { // Some exception happens during the call, do some clean up TraceHelper.TraceEvent(recoverInfo.SessionId, System.Diagnostics.TraceEventType.Error, "[BrokerManager] CreateBrokerDomainAndRun: Failed : {0}\nRevert change...", e); // Bug 5378: If the broker is raised because of attaching (failover), revert it to suspend but not finished state RevertCreateDomainAndRun(info, attached); throw; } return(info.InitializationResult); }
/// <summary> /// Initializes a new instance of the RequestReplyFrontEnd class /// </summary> /// <param name="listenUri">uri the frontend listen to</param> /// <param name="binding">binding that the frontend uses</param> public RequestReplyFrontEnd(Uri listenUri, Binding binding, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, SharedData sharedData) : base(listenUri.AbsoluteUri, observer, clientManager, brokerAuth, sharedData) { this.listener = binding.BuildChannelListener <T>(listenUri); this.acceptChannel = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.AcceptChannel, this).CallbackRoot; this.receiveRequest = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.ReceiveRequest, this).CallbackRoot; }
/// <summary> /// Run the broker /// </summary> /// <param name="startInfo">session start info</param> /// <param name="brokerInfo">indicate the broker start info</param> /// <returns>initialization result</returns> public BrokerInitializationResult Run(SessionStartInfoContract startInfo, BrokerStartInfo brokerInfo) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Information, 0, "[BrokerEntry] Broker is starting initialization, ID = {0}", brokerInfo.SessionId); try { BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: ClusterTopology is {0}", brokerInfo.NetworkTopology); // Step 1: Initialize configuration and shared data ServiceConfiguration serviceConfig; BrokerConfigurations brokerConfig; BindingsSection bindings; SoaCommonConfig.WithoutSessionLayer = startInfo.IsNoSession; // TODO: this is a hack. Working mode should be decided by something like a *SchedulerType* filed. ConfigurationHelper.LoadConfiguration(startInfo, brokerInfo, out brokerConfig, out serviceConfig, out bindings); this.sharedData = new SharedData(brokerInfo, startInfo, brokerConfig, serviceConfig); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 1: Loading configuration and shared data succeeded."); Debug.WriteLine($"[BrokerEntry](Debug) UseAad:{startInfo.UseAad}"); // Step 2: Initialize broker queue ClientInfo[] clientInfo; this.brokerQueueFactory = BrokerEntry.InitBrokerQueue(this.sharedData, out clientInfo); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 2: Initialize broker queue succeeded."); // Step 3: Initialize observer this.observer = new BrokerObserver(this.sharedData, clientInfo); this.sharedData.Observer = this.observer; BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 3: Initialize broker observer succeeded."); // Step 4: Initialize state manager this.stateManager = new BrokerStateManager(this.sharedData, clientInfo.Length != 0); this.stateManager.UnloadBroker += this.UnloadBroker; BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 4: Initialize broker state manager succeeded."); // Step 5: Initialize service job monitor var context = TelepathyContext.GetOrAdd(this.sharedData.BrokerInfo.Headnode); if (SoaCommonConfig.WithoutSessionLayer) { this.monitor = new DummyServiceJobMonitor(this.sharedData, this.stateManager, this.nodeMappingData, context); } else { this.monitor = new ServiceJobMonitor.ServiceJobMonitor(this.sharedData, this.stateManager, this.nodeMappingData, context); } BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 5: Initialize service job monitor succeeded."); // Step 6: Initalize broker authorization this.brokerAuth = BrokerEntry.BuildBrokerAuthorization(this.sharedData); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 6: Initialize broker authorization succeeded."); // Step 7: Initialize dispatcher manager DispatcherManager dispatcherManager = new DispatcherManager(bindings, this.sharedData, this.observer, this.monitor, this.brokerQueueFactory, context); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 7: Initialize dispatcher manager succeeded."); // Step 8: Start service job monitor this.monitor.Start(startInfo, dispatcherManager, this.observer).GetAwaiter().GetResult(); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 8: Start service job monitor succeeded."); // Step 9: Initailize client manager this.clientManager = new BrokerClientManager(clientInfo, this.brokerQueueFactory, this.observer, this.stateManager, this.monitor, this.sharedData); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 9: Initialize client manager succeeded."); // if using AzureQueue, retrieve the connection string and build the request and response message queues if not exist string[] requestQueueUris = { }; string requestBlobUri = string.Empty; string controllerRequestQueueUri = string.Empty; string controllerResponseQueueUri = string.Empty; if (startInfo.UseAzureStorage) { int clusterHash = 0; if (!string.IsNullOrEmpty(brokerInfo.ClusterId)) { string clusterIdString = brokerInfo.ClusterId.ToLowerInvariant(); clusterHash = clusterIdString.GetHashCode(); } else if (!string.IsNullOrEmpty(brokerInfo.ClusterName)) { string clusterNameString = brokerInfo.ClusterName.ToLowerInvariant(); clusterHash = clusterNameString.GetHashCode(); } else { throw new InvalidOperationException($"Both {nameof(brokerInfo.ClusterId)} and {nameof(brokerInfo.ClusterName)} are null or empty. No {nameof(clusterHash)} can be determined."); } if (!string.IsNullOrEmpty(brokerInfo.AzureStorageConnectionString)) { this.azureQueueProxy = new AzureQueueProxy(brokerInfo.ClusterName, clusterHash, this.SessionId, brokerInfo.AzureStorageConnectionString); requestQueueUris = this.azureQueueProxy.RequestQueueUris; requestBlobUri = this.azureQueueProxy.RequestBlobUri; var requestQName = CloudQueueConstants.GetBrokerWorkerControllerRequestQueueName(this.SessionId); var responseQName = CloudQueueConstants.GetBrokerWorkerControllerResponseQueueName(this.SessionId); controllerRequestQueueUri = CloudQueueCreationModule.CreateCloudQueueAndGetSas( brokerInfo.AzureStorageConnectionString, requestQName, CloudQueueCreationModule.AddMessageSasPolicy).GetAwaiter().GetResult(); controllerResponseQueueUri = CloudQueueCreationModule.CreateCloudQueueAndGetSas( brokerInfo.AzureStorageConnectionString, responseQName, CloudQueueCreationModule.ProcessMessageSasPolicy).GetAwaiter().GetResult(); if (this.SessionId == SessionStartInfo.StandaloneSessionId) { CloudQueueCreationModule.ClearCloudQueuesAsync(brokerInfo.AzureStorageConnectionString, new[] { requestQName, responseQName }); } } else { BrokerTracing.TraceError("[BrokerEntry] Initialization: Use Azure Queue is specified, however the Azure connection string is not set."); ThrowHelper.ThrowSessionFault(SOAFaultCode.Broker_AzureConnectionStringNotAvailable, SR.Broker_AzureConnectionStringNotAvailable); } } // Step 10: Initialize frontend this.frontendResult = FrontEndBuilder.BuildFrontEnd(this.sharedData, this.observer, this.clientManager, this.brokerAuth, bindings, this.azureQueueProxy); ////this.maxMessageSize = (int)this.frontendResult.MaxMessageSize; ////this.readerQuotas = this.frontendResult.ReaderQuotas; BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 10: Initialize frontend succeeded."); // Step 11: Start frontend, Initialization finished after this step this.OpenFrontend(); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 11: Open frontend succeeded."); // Step 12: Build initialization result and retrun to client BrokerInitializationResult result = BrokerEntry.BuildInitializationResult( this.frontendResult, dispatcherManager, this.sharedData.Config.LoadBalancing.ServiceOperationTimeout, this.sharedData.Config.Monitor.ClientBrokerHeartbeatInterval, this.sharedData.Config.Monitor.ClientBrokerHeartbeatRetryCount, requestQueueUris, requestBlobUri, controllerRequestQueueUri, controllerResponseQueueUri, startInfo.UseAzureStorage); BrokerTracing.TraceVerbose("[BrokerEntry] Initialization: Step 12: Build initialization result suceeded."); BrokerTracing.TraceInfo("[BrokerEntry] Initialization succeeded."); return(result); } catch (Exception ex) { BrokerTracing.TraceError(ex.ToString()); throw; } finally { if (this.sharedData != null) { this.sharedData.InitializationFinished(); } } }
/// <summary> /// Initializes a new instance of the DuplexFrontEnd class /// </summary> /// <param name="listenUri">uri the frontend listen to</param> /// <param name="binding">binding that the frontend uses</param> /// <param name="observer">indicating the broker observer</param> /// <param name="clientManager">indicating the client manager</param> /// <param name="brokerAuth">indicating the broker authorization</param> /// <param name="sharedData">indicating the shared data</param> public DuplexFrontEnd(Uri listenUri, Binding binding, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, SharedData sharedData) : base(listenUri.AbsoluteUri, observer, clientManager, brokerAuth, sharedData) { this.binding = binding; if (sharedData.StartInfo.UseAad) { BindingParameterCollection bindingParms = new BindingParameterCollection(); var serviceCred = new ServiceCredentials(); serviceCred.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, new NonHARegistry().GetSSLThumbprint().GetAwaiter().GetResult()); bindingParms.Add(serviceCred); this.listener = binding.BuildChannelListener <IDuplexSessionChannel>(listenUri, bindingParms); } else if (sharedData.StartInfo.LocalUser.GetValueOrDefault()) { this.listener = binding.BuildChannelListener <IDuplexSessionChannel>(listenUri, new ServiceCredentials().UseInternalAuthenticationAsync(true).GetAwaiter().GetResult()); } else { this.listener = binding.BuildChannelListener <IDuplexSessionChannel>(listenUri); } this.acceptChannel = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.AcceptChannel, this).CallbackRoot; this.receiveRequest = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.ReceiveRequest, this).CallbackRoot; }
/// <summary> /// Initializes a new instance of the RequestReplyFrontEnd class /// </summary> /// <param name="listenUri">uri the frontend listen to</param> /// <param name="binding">binding that the frontend uses</param> public OutputInputFrontEnd(Uri listenUri, Binding binding, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, SharedData sharedData) : base(listenUri.AbsoluteUri, observer, clientManager, brokerAuth, sharedData) { List <BindingElement> elements = new List <BindingElement>(); elements.Add(new OneWayBindingElement()); elements.AddRange(binding.CreateBindingElements()); CustomBinding shapedBinding = new CustomBinding(elements); this.listener = shapedBinding.BuildChannelListener <T>(listenUri); this.acceptChannel = new ReferencedThreadHelper <IAsyncResult>(new AsyncCallback(this.AcceptChannel), this).CallbackRoot; this.receiveRequest = new ReferencedThreadHelper <IAsyncResult>(new AsyncCallback(this.ReceiveRequest), this).CallbackRoot; }
/// <summary> /// Initializes a new instance of the AzureQueueFrontEnd class /// </summary> /// <param name="listenUri">uri the frontend listen to</param> /// <param name="binding">binding that the frontend uses</param> public AzureQueueFrontEnd(AzureQueueProxy proxy, Uri listenUri, BrokerObserver observer, BrokerClientManager clientManager, BrokerAuthorization brokerAuth, SharedData sharedData) : base(listenUri.AbsoluteUri, observer, clientManager, brokerAuth, sharedData) { this.azureQueueProxy = proxy; this.receiveRequest = new BasicCallbackReferencedThreadHelper <IAsyncResult>(this.ReceiveRequest, this).CallbackRoot; }