/// <summary> /// Recreates the publishing proxy after loading the settings againg from the config file /// </summary> /// <param name="publishServiceProxy">The publish service proxy.</param> /// <returns>A newly created publishing proxy client</returns> internal static PublishingServiceClient RecreatePublishingProxy(PublishingServiceClient publishServiceProxy) { try { // Close the communication channel if (publishServiceProxy.State != CommunicationState.Closed) { publishServiceProxy.Close(); } // Wait for retry interval before retrying. Thread.Sleep(RetryInterval); // Reload the configuration for the service ConfigurationManager.RefreshSection("system.serviceModel/client"); ClientSection clientSection = ((ClientSection)ConfigurationManager.GetSection("system.serviceModel/client")); return(new PublishingServiceClient("WSHttpBinding_IPublishingService", clientSection.Endpoints[0].Address.AbsoluteUri)); } catch (Exception ex) { Globals.TraceMessage(TraceEventType.Error, ex.ToString(), TraceMessages.ExceptionCreatingPublishingServiceProxy); } return(new PublishingServiceClient("WSHttpBinding_IPublishingService")); }
/// <summary> /// Initializes a new instance of the <see cref="MessagePublisher"/> class. /// </summary> internal MessagePublisher() { resetEvent = new AutoResetEvent(false); publishingProxy = new PublishingServiceClient("WSHttpBinding_IPublishingService"); publisherThread = new BackgroundWorker(); publisherThread.WorkerSupportsCancellation = true; publisherThread.DoWork += this.WorkerThreadDoWork; publisherThread.RunWorkerAsync(); }
/// <summary> /// Initializes a new instance of the <see cref="Worker"/> class. /// </summary> /// <param name="sqlConnectionString">sql connection string.</param> /// <param name="queueName">Sql broker queue to connect.</param> /// <param name="batchSize">Count of messages to be fetched in a single call.</param> /// <param name="timeOutValue">The time out value.</param> internal Worker(string sqlConnectionString, string queueName, int batchSize, int timeOutValue) { this.sqlConStr = sqlConnectionString; this.queueName = queueName; this.batchSize = batchSize <= 0 ? 1 : batchSize; this.timeOutValue = timeOutValue; this.sqlCmdStr = string.Format(this.sqlCmdStr, this.batchSize, queueName); this.publishingProxy = new PublishingServiceClient("WSHttpBinding_IPublishingService"); // Start a background worker to fetch broker data from the DB. this.workerThread = new BackgroundWorker(); this.workerThread.WorkerSupportsCancellation = true; this.workerThread.DoWork += this.WorkerThreadDoWork; }
/// <summary> /// Pushes the messages to the publishing service. /// </summary> /// <param name="currentChangeMessageCount">The current change message count.</param> private void PushMessages(int currentChangeMessageCount) { if (currentChangeMessageCount <= 0) { return; } using (var databaseContext = new ZentityAdministrationDataContext(Globals.ZentityConnectionString)) { // Fetch the distinct list of resource type names //var distinctResourceTypes = databaseContext.ChangeMessageRecoveries.Select(changeMessage => new {changeMessage.DataModelNamespace, changeMessage.ResourceTypeName}).Distinct().ToArray(); var distinctResourceTypes = (from changeMessage in databaseContext.ChangeMessageRecoveries group changeMessage by new { changeMessage.DataModelNamespace, changeMessage.ResourceTypeName } into groupResType orderby groupResType.Count() select groupResType.Key).Distinct().ToArray(); // Iterate on the resource type names and push the messages for that resource type // to the publishing service. foreach (var resourceType in distinctResourceTypes) { // Keep retrying to send the messages in the list till it is successfully sent to the publishing service bool flagSucceeded = false; int retryCounter = 0; IQueryable <ChangeMessageRecovery> changeMessageListForResourceType = null; do { try { PublishStatus resourceTypePublishStatus = this.publishingProxy.GetPublishingStatusByResourceType(resourceType.DataModelNamespace, resourceType.ResourceTypeName); int messagesSent; if (resourceTypePublishStatus == null || resourceTypePublishStatus.CurrentStage == PublishStage.Completed || resourceTypePublishStatus.CurrentStage == PublishStage.AbortedOnError || resourceTypePublishStatus.CurrentStage == PublishStage.AbortedOnDemand) { // Fetch all messages of a particular resource type changeMessageListForResourceType = databaseContext.ChangeMessageRecoveries.Where(changeMessage => changeMessage.ResourceTypeName == resourceType.ResourceTypeName && changeMessage.DataModelNamespace == resourceType.DataModelNamespace); // Convert the change message list from database into resource change messages for the publishing service var resChangeMessageListForResourceType = changeMessageListForResourceType.ToResourceChangeMessageList(); messagesSent = resChangeMessageListForResourceType.Count(); // Call the publishing service with the resource change message list. string serializedFilePath = SerializeResourceChangeMessageList(resChangeMessageListForResourceType); if (!string.IsNullOrWhiteSpace(serializedFilePath)) { this.publishingProxy.UpdateCollection(serializedFilePath, resourceType.DataModelNamespace, resourceType.ResourceTypeName, null); flagSucceeded = true; } } else { Globals.TraceMessage(TraceEventType.Information, string.Empty, string.Format(TraceMessages.PublishingServiceBusyMessagesWillNotBeSent, resourceType)); break; } Globals.TraceMessage(TraceEventType.Information, string.Empty, string.Format(TraceMessages.MessagesSentToPublishingService, resourceType, messagesSent)); } catch (EndpointNotFoundException ex) { Globals.TraceMessage( TraceEventType.Error, ex.Message, string.Format("{0} {1}", string.Format(TraceMessages.PublishingServiceEndpointUnavailableWithSuggestion, Worker.RetryInterval.Minutes), string.Format(TraceMessages.RetryCount, retryCounter))); } catch (Exception ex) { Globals.TraceMessage( TraceEventType.Error, ex.Message, string.Format("{0} {1}", string.Format(TraceMessages.ExceptionThrownByPublishingService, Worker.RetryInterval.Minutes), string.Format(TraceMessages.RetryCount, retryCounter))); } // If the message couldnt be sent to the publishing service then wait and retry. if (!flagSucceeded) { if (retryCounter < MaxRetryCount) { this.publishingProxy = Worker.RecreatePublishingProxy(this.publishingProxy); retryCounter++; } else { // Break the loop for this ResourceType as the max retry count has been reached. // The messages for this ResourceType will not be deleted and will be retried next time. break; } } } while (flagSucceeded == false); // Remove the messages of a particular resource type from the message list. if (flagSucceeded) { databaseContext.ChangeMessageRecoveries.DeleteAllOnSubmit(changeMessageListForResourceType); databaseContext.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict); } } } }
private void WorkerThreadDoWork(object sender, DoWorkEventArgs e) { try { if (!(string.IsNullOrWhiteSpace(sqlConStr) && string.IsNullOrWhiteSpace(queueName))) { while (!e.Cancel) { string brokerMessage; using (sqlCon = new SqlConnection(sqlConStr)) { sqlCon.Open(); // Call the fetch stored proc. using (sqlCmd = new SqlCommand()) { sqlCmd.Connection = sqlCon; sqlCmd.CommandTimeout = sqlCon.ConnectionTimeout; sqlCmd.CommandText = this.sqlCmdStr; sqlCmd.CommandType = CommandType.StoredProcedure; // Initialize the parameters for the Stored Procedure SqlParameter param1 = sqlCmd.Parameters.Add(new SqlParameter("@Msg", SqlDbType.NVarChar, -1)); param1.Direction = ParameterDirection.Output; SqlParameter param2 = sqlCmd.Parameters.Add(new SqlParameter("@BatchSize", SqlDbType.Int)); param2.Value = this.batchSize; SqlParameter param3 = sqlCmd.Parameters.Add(new SqlParameter("@Timeout", SqlDbType.BigInt)); param3.Value = 5000; // Fire the sql command on the server and raise events. brokerMessage = this.Listen(); this.OnNotifyMessage(brokerMessage); } } // If the message is empty then there are no messages in the broker queue. // The Notification service will go into sleep mode for the timeout value if (string.IsNullOrWhiteSpace(brokerMessage)) { Globals.TraceMessage(TraceEventType.Verbose, string.Empty, string.Format(TraceMessages.BrokerQueueExhausted, timeOutValue)); Thread.Sleep(timeOutValue); // Ping the publishing service. Check for running publish operations. // If publishing is running then dont proceed to SQL Server. Otherwise get new messages from broker queue. while (true) { try { List <PublishStatus> publishStatusTracker = this.publishingProxy.GetAllPublishingStatus(); if (publishStatusTracker != null) { var statusList = from item in publishStatusTracker where (item.CurrentStage != PublishStage.Completed && item.CurrentStage != PublishStage.AbortedOnError && item.CurrentStage != PublishStage.AbortedOnDemand) select item; if (statusList.Count() == 0) { break; } Globals.TraceMessage(TraceEventType.Verbose, string.Empty, string.Format(TraceMessages.PublishingServiceBusyGoingToSleep, RetryInterval.TotalSeconds)); } Thread.Sleep(RetryInterval); } catch (TimeoutException ex) { Globals.TraceMessage(TraceEventType.Error, ex.Message, string.Format(TraceMessages.PublishingServiceEndpointUnavailableAfterTimeout)); } catch (EndpointNotFoundException ex) { Globals.TraceMessage(TraceEventType.Error, ex.Message, string.Format(TraceMessages.PublishingServiceEndpointUnavailableWithSuggestion, RetryInterval.Minutes)); this.publishingProxy = RecreatePublishingProxy(this.publishingProxy); } catch (Exception ex) { Globals.TraceMessage(TraceEventType.Error, ex.ToString(), string.Format(TraceMessages.ExceptionThrownByPublishingService, RetryInterval.Minutes)); this.publishingProxy = RecreatePublishingProxy(this.publishingProxy); } } } } } } catch (SqlException ex) { Globals.TraceMessage(TraceEventType.Error, ex.ToString(), TraceMessages.ExceptionCallingStoredProcedure); } catch (Exception ex) { Globals.TraceMessage(TraceEventType.Error, ex.ToString(), TraceMessages.ExceptionInWorkerThread); } }