/// <summary> /// Process a collection of queue messages. /// </summary> /// <param name="messages">collection of the queue messages</param> private void ProcessMessages(IEnumerable <CloudQueueMessage> messages) { BrokerTracing.TraceInfo(SoaHelper.CreateTraceMessage("Proxy", "ProcessMessages", string.Format("Process {0} messages.", messages.Count <CloudQueueMessage>()))); messages.AsParallel <CloudQueueMessage>() .ForAll <CloudQueueMessage>( (requestQueueMessage) => { Message request = null; try { BrokerTracing.TraceInfo(string.Format("SOA broker proxy perf1 - {0}", DateTime.UtcNow.TimeOfDay.TotalSeconds)); request = this.requestStorageClients.First().GetWcfMessageFromQueueMessage(requestQueueMessage); this.requestMessageQueue.Add(request); // this.requestMessageQueue.Enqueue(request); UniqueId messageId = SoaHelper.GetMessageId(request); BrokerTracing.TraceInfo(SoaHelper.CreateTraceMessage("Proxy", "Request received inqueue", string.Empty, messageId, "Request message in queue")); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "ProcessMessages", string.Format("Error occurs {0}", e))); } }); this.semaphoreForWorker.Release(); }
/// <summary> /// Get requests from the local cache and spawn a thread to process /// them. /// </summary> /// <remarks> /// Can add throttling logic in the method, but now no need, because /// broker proxy doesn't hit limit of CPU, Memory or Network. /// </remarks> private void MessageProcessor() { try { while (true) { this.semaphoreForResponse.WaitOne(); IEnumerable <CloudQueueMessage> messages; if (this.responseCache.TryDequeue(out messages)) { this.semaphoreForWorker.WaitOne(); ThreadPool.QueueUserWorkItem((s) => { this.ProcessMessages(messages); }); } } } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "MessageProcessor", string.Format("Error occurs, {0}", e))); } }
/// <summary> /// Set the trace level according to the env var /// </summary> public static void SetTraceSwitchLevel() { SourceLevels level = Utility.GetTraceSwitchLevel(); ServiceContext.Logger.Switch.Level = level; if (level != SourceLevels.Off) { RuntimeTraceHelper.IsDiagTraceEnabled = x => true; RuntimeTraceHelper.TraceEvent( TraceEventType.Information, SoaHelper.CreateTraceMessage( "Utility", "SetTraceSwitchLevel", "Add the SoaDiagTraceListener.")); ServiceContext.Logger.Listeners.Add(new SoaDiagTraceListener(Utility.GetJobId())); } else { RuntimeTraceHelper.TraceEvent( TraceEventType.Information, SoaHelper.CreateTraceMessage( "Utility", "SetTraceSwitchLevel", "SoaDiagTrace is disabled.")); } }
/// <summary> /// Start the timer. /// </summary> private void TriggerTimer() { if (this.stop) { lock (this.timerStopLock) { if (this.stop) { this.timerStopped = true; BrokerTracing.TraceInfo( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "TriggerTimer", "Worker stops.")); return; } else { this.timerStopped = false; } } } try { BrokerTracing.TraceInfo( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "TriggerTimer", "Timer triggered with sleep time {0}.", this.sleepPeriod)); this.timer.Change(this.sleepPeriod, Timeout.Infinite); if (this.sleepPeriod == 0) { this.sleepPeriod = MinSleepTime; } else { this.sleepPeriod *= 2; if (this.sleepPeriod > MaxSleepTime) { this.sleepPeriod = MaxSleepTime; } } } catch (NullReferenceException) { TraceUtils.TraceWarning( "MessageSender.Worker", "TriggerTimer", "NullReferenceException occurs when timer is being disposed."); } catch (Exception e) { TraceUtils.TraceError("MessageSender.Worker", "TriggerTimer", "Error occurs, {0}", e); } }
/// <summary> /// Process a collection of queue messages. /// </summary> /// <param name="messages">collection of the queue messages</param> private void ProcessMessages(IEnumerable <CloudQueueMessage> messages) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "ProcessMessages", string.Format("Process {0} messages.", messages.Count <CloudQueueMessage>()))); messages.AsParallel <CloudQueueMessage>().ForAll <CloudQueueMessage>( (responseQueueMessage) => { Message response = null; try { SessionBase.TraceSource.TraceInformation( string.Format("SOA broker proxy perf1 - {0}", DateTime.UtcNow.TimeOfDay.TotalSeconds)); response = this.responseStorageClient.GetWcfMessageFromQueueMessage(responseQueueMessage); var qkey = Tuple.Create(SoaHelper.GetClientDataHeaderFromMessage(response)); if (!this.responseMessageQueues.ContainsKey(qkey)) { lock (this.responseMessageQueues) { if (!this.responseMessageQueues.ContainsKey(qkey)) { this.responseMessageQueues.Add(qkey, new ConcurrentQueue <Message>()); } } } this.responseMessageQueues[qkey].Enqueue(response); UniqueId messageId = SoaHelper.GetMessageId(response); SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Response received inqueue", string.Empty, messageId, "Response message in queue")); // do not delete the message from the queue here, depends on the long invisable timeout and hourly cleanup // this.responseStorageClient.DeleteMessageAsync(responseQueueMessage, messageId); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "ProcessMessages", string.Format("Error occurs {0}", e))); } }); this.semaphoreForWorker.Release(); }
/// <summary> /// Callback method of the message retriever. /// </summary> /// <param name="messages">a collection of messages</param> private void HandleMessages(IEnumerable <CloudQueueMessage> messages) { try { this.requestCache.Enqueue(messages); this.semaphoreForRequest.Release(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "HandleMessages", string.Format("Error occurs, {0}", e))); } }
/// <summary> /// Get the full path of the local cache for the service config file, /// which is specified by Constant.ServiceConfigFileNameEnvVar. /// </summary> /// <returns>local cache folder path</returns> public static string GetServiceLocalCacheFullPath() { string path = SoaHelper.GetCcpPackageRoot(); if (string.IsNullOrEmpty(path)) { RuntimeTraceHelper.TraceEvent( TraceEventType.Error, SoaHelper.CreateTraceMessage( "Utility", "GetServiceLocalCacheFullPath", "The env var CCP_PACKAGE_ROOT has no value")); } else { if (Directory.Exists(path)) { string configFileName = Environment.GetEnvironmentVariable(Constant.ServiceConfigFileNameEnvVar); if (string.IsNullOrEmpty(configFileName)) { RuntimeTraceHelper.TraceEvent( TraceEventType.Error, SoaHelper.CreateTraceMessage( "Utility", "GetServiceLocalCacheFullPath", "The env var CCP_SERVICE_CONFIG_FILENAME has no value")); } else { string subFolderName = Path.GetFileNameWithoutExtension(configFileName); string result = FindLatestSubDirectory(Path.Combine(path, subFolderName)); if (!string.IsNullOrEmpty(result) && Directory.Exists(result)) { return(result); } } } } // fall back to the home folder, which stores the build-in CcpEchoSvc and HpcSeviceHost.exe string home = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); RuntimeTraceHelper.TraceEvent( TraceEventType.Information, SoaHelper.CreateTraceMessage( "Utility", "GetServiceLocalCacheFullPath", string.Format(CultureInfo.InvariantCulture, "Fall back to the home folder {0}.", home))); return(home); }
/// <summary> /// Callback method of the message retriever. /// </summary> /// <param name="messages">a collection of messages</param> private void HandleMessages(IEnumerable <CloudQueueMessage> messages) { try { this.responseCache.Enqueue(messages); this.semaphoreForResponse.Release(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "HandleMessages", string.Format("Error occurs, {0}", e))); } }
public static void TraceVerbose(string className, string methodName, string format, params object[] args) { string traceMessage = SoaHelper.CreateTraceMessage(className, methodName, format, args); #if PROXY Microsoft.Hpc.BrokerProxy.AzureBrokerProxyTrace.WriteLine(traceMessage); #elif DATAPROXY Microsoft.Hpc.Scheduler.Session.Data.Internal.DataProxyTrace.TraceVerbose(traceMessage); #elif DATASVC Microsoft.Hpc.Scheduler.Session.Data.Internal.DataServiceTraceHelper.TraceEvent(TraceEventType.Verbose, traceMessage); #elif CONSOLE Console.Out.WriteLine(string.Format("{0} - {1}", DateTime.Now, traceMessage)); #else BrokerTracing.TraceVerbose(traceMessage); #endif }
/// <summary> /// Get switch level from job env var. /// </summary> /// <returns>trace level</returns> private static SourceLevels GetTraceSwitchLevel() { string values = Environment.GetEnvironmentVariable(Constant.TraceSwitchValue); RuntimeTraceHelper.TraceEvent( TraceEventType.Information, "{0}={1}", Constant.TraceSwitchValue, values); SourceLevels level = SourceLevels.Off; if (!string.IsNullOrEmpty(values)) { string[] levelStrings = values.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string value in levelStrings) { try { level |= (SourceLevels)Enum.Parse(typeof(SourceLevels), value, true); } catch (ArgumentException) { RuntimeTraceHelper.TraceEvent( TraceEventType.Error, SoaHelper.CreateTraceMessage( "Utility", "GetTraceSwitchLevel", string.Format(CultureInfo.CurrentCulture, "{0} is not a correct value of SourceLevels.", value))); return(SourceLevels.Off); } } RuntimeTraceHelper.TraceEvent( TraceEventType.Information, SoaHelper.CreateTraceMessage( "Utility", "GetTraceSwitchLevel", string.Format(CultureInfo.InvariantCulture, "The trace switch level is {0}.", level))); } return(level); }
/// <summary> /// Get requests from the local cache and spawn a thread to process /// them. /// </summary> /// <remarks> /// Can add throttling logic in the method, but now no need, because /// broker proxy doesn't hit limit of CPU, Memory or Network. /// </remarks> private void MessageProcessor(object t) { try { CancellationToken token = (CancellationToken)t; while (!token.IsCancellationRequested) { this.semaphoreForRequest.WaitOne(); IEnumerable <CloudQueueMessage> messages; if (this.requestCache.TryDequeue(out messages)) { this.semaphoreForWorker.WaitOne(); ThreadPool.QueueUserWorkItem((s) => { this.ProcessMessages(messages); }); } } } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "MessageProcessor", string.Format("Error occurs, {0}", e))); } }
/// <summary> /// Add response info back to the local cache for retry next time. /// </summary> /// <param name="result">response info</param> /// <param name="messageId">WCF message id of response</param> /// <param name="eprString">endpoint string of the message</param> private void RetryAddRequest(Message requestMessage) { if (requestMessage != null) { try { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "RetryAddResponse", "Add response back to the local cache.")); this.requestMessages.Enqueue(requestMessage); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "RetryAddResponse", "Error occurs, {0}", e)); } } }
/// <summary> /// Add response info back to the local cache for retry next time. /// </summary> /// <param name="result">response info</param> /// <param name="messageId">WCF message id of response</param> /// <param name="eprString">endpoint string of the message</param> private void RetryAddResponse(Message responseMessage, Tuple <ConcurrentQueue <Message>, AzureStorageClient> messageClient) { if (responseMessage != null) { try { BrokerTracing.TraceError( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "RetryAddResponse", "Add response back to the local cache.")); messageClient.Item1.Enqueue(responseMessage); } catch (Exception e) { BrokerTracing.TraceError( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "RetryAddResponse", "Error occurs, {0}", e)); } } }
/// <summary> /// Cleanup current object. /// </summary> private void Cleanup() { foreach (var messageSender in this.messageSenders) { if (messageSender != null) { try { messageSender.Close(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Closing message retriever failed, {0}", e))); } // this.messageSenders = null; } } if (this.messageRetriever != null) { try { this.messageRetriever.Close(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Closing message retrier failed, {0}", e))); } this.messageRetriever = null; } if (this.messageProcessorTask != null) { try { this.messageProcessorTask.Dispose(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Disposing message processor task failed, {0}", e))); } this.messageProcessorTask = null; } if (this.semaphoreForResponse != null) { try { this.semaphoreForResponse.Dispose(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Disposing semaphoreForRequest failed, {0}", e))); } this.semaphoreForResponse = null; } if (this.semaphoreForWorker != null) { try { this.semaphoreForWorker.Dispose(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Disposing semaphoreForWorker failed, {0}", e))); } this.semaphoreForWorker = null; } foreach (var requestStorageClient in this.requestStorageClients) { if (requestStorageClient != null) { try { requestStorageClient.Close(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Disposing semaphoreForWorker failed, {0}", e))); } //requestStorageClients = null; } } if (this.responseStorageClient != null) { try { this.responseStorageClient.Close(); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "Proxy", "Cleanup", string.Format("Disposing responseStorageClient failed, {0}", e))); } this.responseStorageClient = null; } }
/// <summary> /// Callback method of CloudQueue.BeginAddMessage. Proxy attempts to /// add the message to response queue. /// </summary> /// <param name="ar">async result object</param> private void AddMessageCallback(IAsyncResult ar) { UniqueId messageId; Message requestMessage = null; try { var reliableState = ar.AsyncState as ReliableQueueClient.ReliableState; requestMessage = reliableState.State as Message; messageId = reliableState.MessageId; try { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "Call EndAddMessage to complete adding response message to queue.")); this.requestStorageClient.EndAddMessage(ar); // reset the time sleep time to MinSleepTime this.sleepPeriod = MinSleepTime; } catch (TimeoutException e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "TimeoutException occurs, {0}", e)); // if the callback is lost, EndAddMessage method above // throws TimeoutException, so have a retry here. this.RetryAddRequest(requestMessage); // not sure why return here, suppose need to TriggerTimer return; } finally { this.waitHandler.Set(); } this.InternalBeginAddRequest(null); } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "Error occurs, {0}", e)); this.RetryAddRequest(requestMessage); this.TriggerTimer(); } }
/// <summary> /// Async Pattern. Callback of BeginProcessMessage method. /// </summary> /// <param name="state">state object</param> private void InternalBeginAddRequest(object state) { Message requestMessage = null; SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddRequest", "Request queue length is {0}.", this.requestMessages.Count)); try { if (!this.requestMessages.TryDequeue(out requestMessage)) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddRequest", "Local response cache is empty.")); } } catch (Exception e) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddRequest", string.Format("Failed to get response from local cache, {0}", e))); } if (requestMessage == null) { SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddRequest", string.Format("Get null request from local cache, trigger the time to wait"))); this.TriggerTimer(); return; } try { UniqueId messageId = SoaHelper.GetMessageId(requestMessage); if (messageId == null) { messageId = new UniqueId(); } ReliableQueueClient.ReliableState reliableState = new ReliableQueueClient.ReliableState(requestMessage, messageId); byte[] messageData; using (requestMessage) { messageData = AzureQueueMessageItem.Serialize(requestMessage); } this.waitHandler.Reset(); this.requestStorageClient.BeginAddMessage(messageData, messageId, this.AddMessageCallback, reliableState); } catch (Exception e) { this.waitHandler.Set(); SessionBase.TraceSource.TraceInformation( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddRequest", "Failed to add response message, {0}", e)); this.TriggerTimer(); } }
/// <summary> /// Async Pattern. Callback of BeginProcessMessage method. /// </summary> /// <param name="state">state object</param> private void InternalBeginAddResponse(object state) { Message responseMessage = null; Tuple <ConcurrentQueue <Message>, AzureStorageClient> messageClient = null; try { foreach (Tuple <ConcurrentQueue <Message>, AzureStorageClient> responseMessageClient in this.responseMessageClients.Values) { if (!responseMessageClient.Item1.TryDequeue(out responseMessage)) { BrokerTracing.TraceInfo( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddResponse", "Local response cache is empty.")); } else { messageClient = responseMessageClient; break; } } } catch (Exception e) { BrokerTracing.TraceError( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddResponse", string.Format("Failed to get response from local cache, {0}", e))); } if (responseMessage == null) { this.TriggerTimer(); return; } BrokerTracing.TraceInfo( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddResponse", "Retrieved message from local response cache.")); try { UniqueId messageId = SoaHelper.GetMessageId(responseMessage); if (messageId == null) { messageId = new UniqueId(); } ReliableQueueClient.ReliableState reliableState = new ReliableQueueClient.ReliableState(responseMessage, messageClient, messageId); this.waitHandler.Reset(); byte[] messageData; using (responseMessage) { messageData = AzureQueueMessageItem.Serialize(responseMessage); } messageClient.Item2.BeginAddMessage(messageData, messageId, this.AddMessageCallback, reliableState); } catch (Exception e) { this.waitHandler.Set(); BrokerTracing.TraceError( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "InternalBeginAddResponse", "Failed to add response message, {0}", e)); this.TriggerTimer(); } }
/// <summary> /// Callback method of CloudQueue.BeginAddMessage. Proxy attempts to /// add the message to response queue. /// </summary> /// <param name="ar">async result object</param> private void AddMessageCallback(IAsyncResult ar) { UniqueId messageId; Message responseMessage = null; Tuple <ConcurrentQueue <Message>, AzureStorageClient> messageClient = null; try { var reliableState = ar.AsyncState as ReliableQueueClient.ReliableState; responseMessage = reliableState.State as Message; messageId = reliableState.MessageId; messageClient = reliableState.MessageClient; try { BrokerTracing.TraceInfo( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "Call EndAddMessage to complete adding response message to queue.")); messageClient.Item2.EndAddMessage(ar); } catch (TimeoutException e) { BrokerTracing.TraceWarning( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "TimeoutException occurs, {0}", e)); // if the callback is lost, EndAddMessage method above // throws TimeoutException, so have a retry here. this.RetryAddResponse(responseMessage, messageClient); return; } finally { this.waitHandler.Set(); } this.InternalBeginAddResponse(null); } catch (Exception e) { BrokerTracing.TraceError( SoaHelper.CreateTraceMessage( "MessageSender.Worker", "AddMessageCallback", "Error occurs, {0}", e)); this.RetryAddResponse(responseMessage, messageClient); this.TriggerTimer(); } }
/// <summary> /// Cleanup current object. /// </summary> private void Cleanup() { if (this.messageSender != null) { try { this.messageSender.Close(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Closing message retriever failed, {0}", e))); } this.messageSender = null; } foreach (var messageRetriever in this.messageRetrievers) { if (messageRetriever != null) { try { messageRetriever.Close(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Closing message retrier failed, {0}", e))); } // messageRetriever = null; } } if (this.messageProcessorTask != null) { if (this.taskCancellation != null) { try { using (this.taskCancellation) { this.taskCancellation.Cancel(); // no need to wait here for the task could be waiting for the semaphore // this.messageProcessorTask.Wait(WaitTimeForTaskInMillisecond, this.taskCancellation.Token); } } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Cancelling messageProcessorTask failed, {0}", e))); } } try { // the Task cannot be disposed when it is not in a cmpletion state // this.messageProcessorTask.Dispose(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Disposing message processor task failed, {0}", e))); } this.messageProcessorTask = null; } if (this.semaphoreForRequest != null) { try { this.semaphoreForRequest.Dispose(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Disposing semaphoreForRequest failed, {0}", e))); } this.semaphoreForRequest = null; } if (this.semaphoreForWorker != null) { try { this.semaphoreForWorker.Dispose(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Disposing semaphoreForWorker failed, {0}", e))); } this.semaphoreForWorker = null; } foreach (var requestStorageClient in this.requestStorageClients) { if (requestStorageClient != null) { try { requestStorageClient.Close(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Disposing requestStorageClient failed, {0}", e))); } // requestStorageClient = null; } } if (this.responseStorageClient != null) { try { this.responseStorageClient.Close(); } catch (Exception e) { BrokerTracing.TraceError(SoaHelper.CreateTraceMessage("Proxy", "Cleanup", string.Format("Disposing responseStorageClient failed, {0}", e))); } this.responseStorageClient = null; } this.requestMessageQueue?.Dispose(); }
/// <summary> /// Get service assembly file /// </summary> /// <param name="serviceConfigName">indicating service configuration file</param> /// <param name="onAzure">on azure or in on-premise cluster</param> /// <param name="registration">output service registration instance</param> /// <param name="serviceAssemblyFullPath">full path of the soa service assembly</param> /// <returns>returns return code</returns> public static int GetServiceRegistration(string serviceConfigName, bool onAzure, out ServiceRegistration registration, out string serviceAssemblyFullPath) { // Open the service registration configuration section ExeConfigurationFileMap map = new ExeConfigurationFileMap(); map.ExeConfigFilename = serviceConfigName; Configuration config = null; RetryManager.RetryOnceAsync( () => config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None), TimeSpan.FromSeconds(1), ex => ex is ConfigurationErrorsException) .GetAwaiter() .GetResult(); Debug.Assert(config != null, "Configuration is not opened properly."); registration = ServiceRegistration.GetSectionGroup(config); serviceAssemblyFullPath = registration.Service.AssemblyPath; if (!string.IsNullOrEmpty(serviceAssemblyFullPath)) { serviceAssemblyFullPath = Environment.ExpandEnvironmentVariables(serviceAssemblyFullPath); } if (onAzure) { bool exists = false; try { exists = File.Exists(serviceAssemblyFullPath); } catch (Exception e) { RuntimeTraceHelper.TraceEvent( TraceEventType.Error, SoaHelper.CreateTraceMessage( "Utility", "GetServiceLocalCacheFullPath", string.Format("Exception happens when check the file existence. {0}", e))); } if (!exists) { // If we find the service registration file under the specified path, use it. // Otherwise, fall back to the package root folder. The service assembly is under the same folder as the registration file. serviceAssemblyFullPath = Path.Combine(Path.GetDirectoryName(serviceConfigName), Path.GetFileName(serviceAssemblyFullPath)); } } if (string.IsNullOrEmpty(serviceAssemblyFullPath)) { string message = string.Format(CultureInfo.CurrentCulture, StringTable.AssemblyFileNotRegistered, serviceConfigName); Console.Error.WriteLine(message); RuntimeTraceHelper.TraceEvent(TraceEventType.Error, message); return(ErrorCode.ServiceHost_AssemblyFileNameNullOrEmpty); } if (!File.Exists(serviceAssemblyFullPath)) { // If the obtained service assembly path is not valid or not existing string message = string.Format(CultureInfo.CurrentCulture, StringTable.AssemblyFileCantFind, serviceAssemblyFullPath); Console.Error.WriteLine(message); RuntimeTraceHelper.TraceEvent(TraceEventType.Error, message); return(ErrorCode.ServiceHost_AssemblyFileNotFound); } return(ErrorCode.Success); }