/// <summary> /// Gets a broker process from the pool /// </summary> /// <returns>returns a broker process</returns> /// <remarks>this method is thread safe</remarks> public BrokerProcess GetBrokerProcess() { // Create a new broker process in another thread ThreadPool.QueueUserWorkItem(this.createNewBrokerProcessCallback); DateTime st = DateTime.Now; while (true) { if (this.pool.Count > 0) { lock (this.pool) { if (this.pool.Count > 0) { // Gets the last process BrokerProcess process = this.pool[this.pool.Count - 1]; process.Exited -= this.BrokerProcess_Exited; this.pool.RemoveAt(this.pool.Count - 1); TraceHelper.TraceEvent(TraceEventType.Information, "[BrokerProcessPool] Fetched broker process, PID = {0}", process.Id); return(process); } } } if (!this.newBrokerProcessReadyEvent.WaitOne(WaitForNewProcessTimeout, false)) { if ((int)DateTime.Now.Subtract(st).TotalMilliseconds > GetBrokerProcessTimeout) { ThrowHelper.ThrowSessionFault(SOAFaultCode.TimeoutToGetBrokerWorkerProcess, SR.TimeoutToGetBrokerWorkerProcess); } } } }
/// <summary> /// Create new broker process /// </summary> private void CreateNewBrokerProcess(object state) { BrokerProcess process = new BrokerProcess(); process.Ready += new EventHandler <BrokerProcessReadyEventArgs>(this.BrokerProcess_Ready); process.Exited += new EventHandler(this.BrokerProcess_Exited); process.Start(); }
/// <summary> /// Create custom broker process /// </summary> /// <param name="customBrokerRegistration">indicating the custom broker registration</param> /// <returns>returns the broker process object</returns> private static BrokerProcess CreateCustomBrokerProcess(CustomBrokerRegistration customBroker) { BrokerProcess process = new BrokerProcess(customBroker.Executive, customBroker.EnvironmentVariables); process.Start(); process.WaitForReady(); return(process); }
/// <summary> /// Event triggered when broker process is ready /// </summary> /// <param name="sender">indicating the sender</param> /// <param name="e">indicating the event args</param> private void BrokerProcess_Ready(object sender, BrokerProcessReadyEventArgs e) { BrokerProcess process = (BrokerProcess)sender; Debug.Assert(process != null, "[BrokerProcessPool] Sender should be an instance of BrokerProcess class."); if (e.TimedOut) { TraceHelper.RuntimeTrace.LogBrokerWorkerProcessFailedToInitialize(process.Id); int count = Interlocked.Decrement(ref this.currentPoolSize); Debug.Assert(count >= 0, "[BrokerProcessPool] Current pool size should always be non-negative."); process.Close(); } else { lock (this.pool) { if (this.disposed) { return; } // // Insert into the list in descending order // This way we can always tell which broker process will be used - it will be always the one with lowest pid // I didn't use SortedList because SortedList needs to be unique in key and there might be a chance where old // process died but is not yet removed from the list while a new process with the exact same PID goes into the // list and lead to exception. // int indexToInsert = 0; int id = process.Id; while (indexToInsert < this.pool.Count) { if (id >= this.pool[indexToInsert].Id) { break; } indexToInsert++; } this.pool.Insert(indexToInsert, process); } this.newBrokerProcessReadyEvent.Set(); TraceHelper.RuntimeTrace.LogBrokerWorkerProcessReady(process.Id); int count = Interlocked.Increment(ref this.currentPoolSize); if (count <= this.poolSize) { ThreadPool.QueueUserWorkItem(this.createNewBrokerProcessCallback); } else { Interlocked.Decrement(ref this.currentPoolSize); } } }
/// <summary> /// Event triggered when broker process is exited /// </summary> /// <param name="sender">indicating the sender</param> /// <param name="e">indicating the event args</param> private void BrokerProcess_Exited(object sender, EventArgs e) { BrokerProcess process = (BrokerProcess)sender; Debug.Assert(process != null, "[BrokerProcessPool] Sender should be an instance of BrokerProcess class."); TraceHelper.RuntimeTrace.LogBrokerWorkerProcessFailedToInitialize(process.Id); lock (this.pool) { if (this.disposed) { return; } this.pool.Remove(process); } int count = Interlocked.Decrement(ref this.currentPoolSize); Debug.Assert(count >= 0, "[BrokerProcessPool] Current pool size should always be non-negative."); }
/// <summary> /// Start broker process /// </summary> public void StartBroker() { bool failoverMode = false; if (Interlocked.Increment(ref this.retryCount) > 1) { // Bug 7150: Need to set attach to true when retrying failoverMode = true; this.brokerInfo.Attached = true; } if (this.customBroker == null || String.IsNullOrEmpty(this.customBroker.Executive)) { this.brokerProcess = this.pool.GetBrokerProcess(); } else { this.brokerProcess = CreateCustomBrokerProcess(this.customBroker); } // Log a trace mapping broker worker pid to session id. TraceHelper.TraceEvent( this.sessionId, TraceEventType.Information, "[BrokerInfo].StartBroker: Init broker worker {0} for session {1}.", this.brokerProcess.Id, this.sessionId); BrokerManagementServiceClient client = this.CreateClient(); try { this.result = client.Initialize(this.sessionStartInfo, this.brokerInfo); // Set broker's unique id to the initialization result when the process // is (re)started. this.result.BrokerUniqueId = this.UniqueId; this.brokerProcess.Exited += new EventHandler(this.BrokerProcess_Exited); } catch (Exception e) { TraceHelper.TraceEvent(this.sessionId, TraceEventType.Error, "[BrokerInfo] Failed to initialize broker: {0}", e.ToString()); // If in failover mode, close this broker and do not retry anymore if (failoverMode) { try { this.CloseBroker(true); } catch (Exception ex) { TraceHelper.TraceEvent(TraceEventType.Warning, "[BrokerInfo].StartBroker: Exception {0}", ex); } } throw; } finally { Utility.AsyncCloseICommunicationObject(client); } }