/// <inheritdoc /> public override void Consume(PageRouteWasUpdatedMessage message) { // Check if Rock is started if (!RockMessageBus.IsRockStarted) { // Don't publish events until Rock is all the way started var logMessage = $"'Page Route Was Updated' message was not consumed because Rock is not fully started."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } // Do not reregister the routes is the message was sent from this node as that has already been done. if (RockMessageBus.IsFromSelf(message)) { RockLogger.Log.Debug(RockLogDomains.Bus, $"Skipping 'Page Route Was Updated Message' because this node ({message.SenderNodeName}) was the publisher."); return; } RockLogger.Log.Debug(RockLogDomains.Bus, $"Consumed 'Page Route Was Updated Message' on node {RockMessageBus.NodeName}."); RockRouteHandler.RemoveRockPageRoutes(); RockRouteHandler.RegisterRoutes(); }
/// <summary> /// Publishes the specified entity. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">The key.</param> /// <param name="region">The region.</param> public static void Publish <T>(string key = null, string region = null) { var message = new CacheWasUpdatedMessage { Key = key, Region = region, CacheTypeName = typeof(T)?.AssemblyQualifiedName, SenderNodeName = RockMessageBus.NodeName }; if (!RockMessageBus.IsRockStarted) { // Don't publish cache events until Rock is all the way started var logMessage = $"Cache Update message was not published because Rock is not fully started yet. {message.ToDebugString()}."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } _ = RockMessageBus.PublishAsync <CacheEventQueue, CacheWasUpdatedMessage>(message); RockLogger.Log.Debug(RockLogDomains.Bus, $"Published Cache Update message. {message.ToDebugString()}."); }
/// <summary> /// Publishes the scheduled transaction event. /// </summary> /// <param name="scheduledTransactionId">The scheduled transaction identifier.</param> /// <param name="eventType">Type of the event.</param> /// <param name="gatewaySupportedCardTypesDefinedValueGuid">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the credit card types supported by the <see cref="FinancialGateway"/> for a specified currency.</param> /// <param name="gatewayCurrencyUnitMultiple">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the "unit multiple" (e.g., 100 for dollars) of the currency specified by the gatway.</param> public static void PublishScheduledTransactionEvent(int scheduledTransactionId, string eventType, Guid?gatewaySupportedCardTypesDefinedValueGuid = null, Guid?gatewayCurrencyUnitMultiple = null) { using (var rockContext = new RockContext()) { var scheduleService = new FinancialScheduledTransactionService(rockContext); var gateway = scheduleService.Queryable() .AsNoTracking() .Include(s => s.FinancialGateway) .Where(s => s.Id == scheduledTransactionId) .Select(s => s.FinancialGateway) .FirstOrDefault(); var gatewayComponent = gateway?.GetGatewayComponent(); var searchKeyTiedGateway = gatewayComponent as ISearchKeyTiedGateway; var searchKeyTypeGuid = searchKeyTiedGateway?.GetPersonSearchKeyTypeGuid(gateway); var data = GetScheduledGiftWasModifiedMessageData(rockContext, scheduledTransactionId, searchKeyTypeGuid, gatewaySupportedCardTypesDefinedValueGuid, gatewayCurrencyUnitMultiple); if (data != null) { var statusGateway = gatewayComponent as IStatusProvidingGateway; var message = new ScheduledGiftWasModifiedMessage { EventType = eventType, Address = data.Address, FinancialScheduledTransaction = data.FinancialScheduledTransaction, Person = data.Person, Time = RockDateTime.Now }; _ = RockMessageBus.PublishAsync <GivingEventQueue, ScheduledGiftWasModifiedMessage>(message); } } }
/// <summary> /// Consumes the specified context. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public virtual Task Consume( ConsumeContext<TMessage> context ) { RockLogger.Log.Debug( RockLogDomains.Core, "Rock Task Consumer: {0} TMessage Type: {1} Context: {@context}", GetType(), typeof( TMessage ), context ); ConsumeContext = context; Consume( context.Message ); return RockMessageBus.GetCompletedTask(); }
/// <summary> /// Receives the remove message from the bus. /// </summary> /// <param name="message">The message.</param> internal void ReceiveRemoveMessage(CacheWasUpdatedMessage message) { if (RockMessageBus.IsFromSelf(message)) { // We already took care of Clearing the cache for our instance, so // we can ignore this message. RockLogger.Log.Debug(RockLogDomains.Bus, $"Cache RemoveMessage was from ourselves( {message.SenderNodeName} ). Skipping. {message.ToDebugString()}."); return; } if (message.Key.IsNullOrWhiteSpace()) { // A Key needs to be specified return; } if (message.Region.IsNotNullOrWhiteSpace()) { CacheManager.Remove(message.Key, message.Region); } else { CacheManager.Remove(message.Key); } }
/// <summary> /// Publishes this instance. /// </summary> public static void Publish() { if (!RockMessageBus.IsRockStarted) { // Don't publish events until Rock is all the way started var logMessage = $"'Page Route Was Updated' message was not published because Rock is not fully started."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } var message = new PageRouteWasUpdatedMessage(); _ = RockMessageBus.PublishAsync <PageRouteEventQueue, PageRouteWasUpdatedMessage>(message); RockLogger.Log.Debug(RockLogDomains.Bus, $"Published 'Page Route Was Updated' message."); }
/// <summary> /// Binds the details. /// </summary> private void BindDetails() { var descriptionList = new DescriptionList(); var transport = RockMessageBus.GetTransportName(); if (!transport.IsNullOrWhiteSpace()) { descriptionList.Add("Transport", transport); } descriptionList.Add("NodeName", RockMessageBus.NodeName); var statLog = RockMessageBus.StatLog; if (statLog != null) { if (statLog.MessagesConsumedLastMinute.HasValue) { descriptionList.Add("Messages Per Minute", statLog.MessagesConsumedLastMinute); } if (statLog.MessagesConsumedLastHour.HasValue) { descriptionList.Add("Messages Per Hour", statLog.MessagesConsumedLastHour); } if (statLog.MessagesConsumedLastDay.HasValue) { descriptionList.Add("Messages Per Day", statLog.MessagesConsumedLastDay); } } lDetails.Text = descriptionList.Html; }
/// <summary> /// Called when the transport receive faults /// </summary> /// <param name="context">The receive context of the message</param> /// <param name="exception">The exception that was thrown</param> /// <returns></returns> public Task ReceiveFault(ReceiveContext context, Exception exception) { var errorMessage = $"A ReceiveFault occurred. Context: {context}. Exception {exception}"; ExceptionLogService.LogException(new BusException(errorMessage, exception)); RockLogger.Log.Error(RockLogDomains.Bus, "A ReceiveFault occurred Context: @context Exception: @exception", context, exception); return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Called when a message being consumed produced a fault /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="context">The message consume context</param> /// <param name="duration">The consumer duration</param> /// <param name="consumerType">The consumer type</param> /// <param name="exception">The exception from the consumer</param> /// <returns></returns> public Task ConsumeFault <T>(ConsumeContext <T> context, TimeSpan duration, string consumerType, Exception exception) where T : class { var errorMessage = $"A ConsumeFault occurred in the {consumerType}. Original Message: {context.Message}. Exception: {exception}"; ExceptionLogService.LogException(new BusException(errorMessage, exception)); RockLogger.Log.Error(RockLogDomains.Bus, "A ConsumeFault occurred in the @consumerType. Original Message: @originalMessage Exception: @exception", consumerType, context.Message, exception); return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Publishes the expiring card and cardholder details /// </summary> /// <param name="person"></param> /// <param name="financialPaymentDetail"></param> /// <param name="financialScheduledTransactions"></param> public static void Publish(Person person, FinancialPaymentDetail financialPaymentDetail, List <int> financialScheduledTransactions) { if (!RockMessageBus.IsRockStarted) { // Don't publish events until Rock is all the way started const string logMessage = "'Credit Card Is Expiring Message' message was not published because Rock is not fully started yet."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } var cardHolder = new CardHolder() { CommunicationPreference = (int)person.CommunicationPreference, Email = person.Email, FirstName = person.FirstName, Id = person.Id, LastName = person.LastName, MiddleName = person.MiddleName, NickName = person.NickName }; var message = new CreditCardIsExpiringMessage { AccountNumberMasked = financialPaymentDetail.AccountNumberMasked, BillingLocation = financialPaymentDetail.BillingLocation?.GetFullStreetAddress(), CardExpirationDate = financialPaymentDetail.CardExpirationDate, CreatedDateTime = financialPaymentDetail.CreatedDateTime, CreditCardTypeValue = financialPaymentDetail.CreditCardTypeValue?.Value, ExpirationDate = financialPaymentDetail.ExpirationDate, ExpirationMonth = financialPaymentDetail.ExpirationMonth, ExpirationYear = financialPaymentDetail.ExpirationYear, FinancialPersonSavedAccountName = financialPaymentDetail.FinancialPersonSavedAccount?.Name, Id = financialPaymentDetail.Id, NameOnCard = financialPaymentDetail.NameOnCard, Person = cardHolder, FinancialScheduledTransactions = financialScheduledTransactions }; _ = RockMessageBus.PublishAsync <ExpiringCardEventQueue, CreditCardIsExpiringMessage>(message); RockLogger.Log.Debug(RockLogDomains.Bus, "Published 'Credit Card Is Expiring Message' message."); }
/// <summary> /// Called after the message has been dispatched to all consumers - note that in the case of an exception /// this method is not called, and the DispatchFaulted method is called instead /// </summary> /// <typeparam name="T"></typeparam> /// <param name="context"></param> /// <returns></returns> public Task PostConsume <T>(ConsumeContext <T> context) where T : class { // Log for the bus as a whole RockMessageBus.StatLog?.LogConsume(); // Log for the specific queue var queue = RockMessage.GetQueue(typeof(T)); queue?.StatLog?.LogConsume(); return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Receives the clear message from the message bus. /// </summary> /// <param name="message">The message.</param> internal void ReceiveClearMessage(CacheWasUpdatedMessage message) { if (RockMessageBus.IsFromSelf(message)) { // We already took care of Clearing the cache for our instance, so // we can ignore this message. RockLogger.Log.Debug(RockLogDomains.Bus, $"Cache ClearMessage was from ourselves( {message.SenderNodeName} ). Skipping. {message.ToDebugString()}."); return; } CacheManager.Clear(); }
/// <summary> /// Publishes the specified entity. /// </summary> /// <param name="senderNodeName">Name of the sender node.</param> /// <param name="messageType">The message.</param> /// <param name="recipientNodeName">Name of the recipient node.</param> /// <param name="payload">The payload.</param> public static void Publish(string senderNodeName, string messageType, string recipientNodeName = "", string payload = "") { var webFarmWasUpdatedMessage = new WebFarmWasUpdatedMessage { SenderNodeName = senderNodeName, MessageType = messageType, RecipientNodeName = recipientNodeName, Payload = payload }; _ = RockMessageBus.PublishAsync <WebFarmQueue, WebFarmWasUpdatedMessage>(webFarmWasUpdatedMessage); }
/// <summary> /// Binds the active label. /// </summary> private void BindActiveLabel() { if (RockMessageBus.IsReady()) { hlActive.Text = "Active"; hlActive.LabelType = Rock.Web.UI.Controls.LabelType.Success; } else { hlActive.Text = "Inactive"; hlActive.LabelType = Rock.Web.UI.Controls.LabelType.Danger; } }
/// <summary> /// Publishes the specified entity. /// </summary> /// <param name="entity">The entity.</param> /// <param name="entityState">State of the entity.</param> public static void Publish(IEntity entity, EntityState entityState) { var entityTypeId = entity.TypeId; var entityType = EntityTypeCache.Get(entityTypeId); var messageType = typeof(EntityWasUpdatedMessage <>).MakeGenericType(entityType.GetEntityType()); var message = Activator.CreateInstance(messageType) as IEntityWasUpdatedMessage; message.EntityId = entity.Id; message.EntityTypeId = entity.TypeId; message.EntityState = entityState.ToString(); _ = RockMessageBus.PublishAsync(message, messageType); }
/// <summary> /// Publishes the gift event. /// </summary> /// <param name="transactionId">The transaction identifier.</param> /// <param name="eventType">Type of the event.</param> /// <param name="gatewaySupportedCardTypesDefinedValueGuid">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the credit card types supported by the <see cref="FinancialGateway"/> for a specified currency.</param> /// <param name="gatewayCurrencyUnitMultiple">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the "unit multiple" (e.g., 100 for dollars) of the currency specified by the gatway.</param> public static void PublishTransactionEvent(int transactionId, string eventType = null, Guid?gatewaySupportedCardTypesDefinedValueGuid = null, Guid?gatewayCurrencyUnitMultiple = null) { using (var rockContext = new RockContext()) { var transactionService = new FinancialTransactionService(rockContext); var gateway = transactionService.Queryable() .AsNoTracking() .Include(t => t.FinancialGateway) .Where(t => t.Id == transactionId) .Select(t => t.FinancialGateway) .FirstOrDefault(); var gatewayComponent = gateway?.GetGatewayComponent(); var searchKeyTiedGateway = gatewayComponent as ISearchKeyTiedGateway; var searchKeyTypeGuid = searchKeyTiedGateway?.GetPersonSearchKeyTypeGuid(gateway); var data = GetGiftWasGivenMessageData(rockContext, transactionId, searchKeyTypeGuid, gatewaySupportedCardTypesDefinedValueGuid, gatewayCurrencyUnitMultiple); if (data != null) { var statusGateway = gatewayComponent as IStatusProvidingGateway; if (eventType.IsNullOrWhiteSpace()) { eventType = statusGateway.IsPendingStatus(data.FinancialTransaction.Status) ? GiftEventTypes.GiftPending : statusGateway.IsSuccessStatus(data.FinancialTransaction.Status) ? GiftEventTypes.GiftSuccess : statusGateway.IsFailureStatus(data.FinancialTransaction.Status) ? GiftEventTypes.GiftFailure : null; } if (!eventType.IsNullOrWhiteSpace()) { var message = new GiftWasGivenMessage { EventType = eventType, Address = data.Address, FinancialTransaction = data.FinancialTransaction, Person = data.Person, Time = RockDateTime.Now }; _ = RockMessageBus.PublishAsync <GivingEventQueue, GiftWasGivenMessage>(message); } } } }
/// <summary> /// Publishes the specified entity. /// </summary> /// <param name="personIds">The person ids.</param> public static void Publish(IEnumerable <int> personIds) { var list = personIds?.ToList(); if (list?.Any() != true) { // Don't publish if there are no person IDs return; } if (!RockMessageBus.IsRockStarted) { // Don't publish events until Rock is all the way started var logMessage = $"'Giving Unit Was Classified' message was not published because Rock is not fully started yet."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } var message = new GivingUnitWasClassifiedMessage { PersonIds = list }; _ = RockMessageBus.PublishAsync <GivingEventQueue, GivingUnitWasClassifiedMessage>(message); RockLogger.Log.Debug(RockLogDomains.Bus, $"Published 'Giving Unit Was Classified' message."); }
/// <summary> /// Called after the message has been dispatched to all consumers when one or more exceptions have occurred /// </summary> /// <typeparam name="T"></typeparam> /// <param name="context"></param> /// <param name="exception"></param> /// <returns></returns> /// <exception cref="NotImplementedException"></exception> public Task ConsumeFault <T>(ConsumeContext <T> context, Exception exception) where T : class { ExceptionLogService.LogException(new BusException($"A Consume Fault occurred. Original Message: {context?.Message}", exception)); RockLogger.Log.Error(RockLogDomains.Core, "A Consume Fault occurred Original Message: @originalMessage Exception: @exception", context.Message, exception); return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Sends the messages to the bus. /// </summary> public static void Publish(this ITransactionWasAlertedMessage message) { _ = RockMessageBus.PublishAsync(message, message.GetType()); }
/// <summary> /// Called when a message has been delivered by the transport is about to be received by the endpoint /// </summary> /// <param name="context">The receive context of the message</param> /// <returns></returns> public Task PreReceive(ReceiveContext context) { return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Called when a message has been consumed by a consumer /// </summary> /// <typeparam name="T">The message type</typeparam> /// <param name="context">The message consume context</param> /// <param name="duration">The consumer duration</param> /// <param name="consumerType">The consumer type</param> /// <returns></returns> public Task PostConsume <T>(ConsumeContext <T> context, TimeSpan duration, string consumerType) where T : class { return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Runs various startup operations that need to run prior to RockWeb startup /// </summary> internal static void RunApplicationStartup() { // Indicate to always log to file during initialization. ExceptionLogService.AlwaysLogToFile = true; InitializeRockOrgTimeZone(); StartDateTime = RockDateTime.Now; RockInstanceConfig.SetApplicationStartedDateTime(StartDateTime); // If there are Task.Runs that don't handle their exceptions, this will catch those // so that we can log it. Note that this event won't fire until the Task is disposed. // In most cases, that'll be when GC is collected. So it won't happen immediately. TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; LogStartupMessage("Application Starting"); var runMigrationFileInfo = new FileInfo(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data\\Run.Migration")); bool hasPendingEFMigrations = runMigrationFileInfo.Exists || HasPendingEFMigrations(); bool ranEFMigrations = MigrateDatabase(hasPendingEFMigrations); ShowDebugTimingMessage("EF Migrations"); ConfigureEntitySaveHooks(); ShowDebugTimingMessage("Configure Entity SaveHooks"); // Now that EF Migrations have gotten the Schema in sync with our Models, // get the RockContext initialized (which can take several seconds) // This will help reduce the chances of multiple instances RockWeb causing problems, // like creating duplicate attributes, or running the same migration in parallel using (var rockContext = new RockContext()) { new AttributeService(rockContext).Get(0); ShowDebugTimingMessage("Initialize RockContext"); } // Configure the values for RockDateTime. RockDateTime.FirstDayOfWeek = Rock.Web.SystemSettings.StartDayOfWeek; InitializeRockGraduationDate(); if (runMigrationFileInfo.Exists) { // fileInfo.Delete() won't do anything if the file doesn't exist (it doesn't throw an exception if it is not there ) // but do the fileInfo.Exists to make this logic more readable runMigrationFileInfo.Delete(); } // Run any plugin migrations bool anyPluginMigrations = MigratePlugins(); ShowDebugTimingMessage("Plugin Migrations"); /* 2020-05-20 MDP * Plugins use Direct SQL to update data, * or other things could have done data updates * So, just in case, clear the cache (which could be Redis) since anything that is in there could be stale */ RockCache.ClearAllCachedItems(false); using (var rockContext = new RockContext()) { LoadCacheObjects(rockContext); ShowDebugTimingMessage("Load Cache Objects"); UpdateAttributesFromRockConfig(rockContext); } if (ranEFMigrations || anyPluginMigrations) { // If any migrations ran (version was likely updated) SendVersionUpdateNotifications(); ShowDebugTimingMessage("Send Version Update Notifications"); } // Start the message bus RockMessageBus.StartAsync().Wait(); var busTransportName = RockMessageBus.GetTransportName(); if (busTransportName.IsNullOrWhiteSpace()) { ShowDebugTimingMessage("Message Bus"); } else { ShowDebugTimingMessage($"Message Bus ({busTransportName})"); } // Start stage 1 of the web farm RockWebFarm.StartStage1(); ShowDebugTimingMessage("Web Farm (stage 1)"); RegisterHttpModules(); ShowDebugTimingMessage("Register HTTP Modules"); // Initialize the Lava engine. InitializeLava(); ShowDebugTimingMessage($"Initialize Lava Engine ({LavaService.CurrentEngineName})"); // setup and launch the jobs infrastructure if running under IIS bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]); if (runJobsInContext) { StartJobScheduler(); ShowDebugTimingMessage("Start Job Scheduler"); } // Start stage 2 of the web farm RockWebFarm.StartStage2(); ShowDebugTimingMessage("Web Farm (stage 2)"); }
/// <summary> /// Called before a message is dispatched to any consumers /// </summary> /// <typeparam name="T"></typeparam> /// <param name="context">The consume context</param> /// <returns></returns> public Task PreConsume <T>(ConsumeContext <T> context) where T : class { return(RockMessageBus.GetCompletedTask()); }
/// <summary> /// Sends the messages to the bus. /// </summary> public static void Send(this BusStartedTaskMessage message) { _ = RockMessageBus.SendAsync(message, message.GetType()); }