List <BrokeredMessage> CreateTrackingMessages(OrchestrationRuntimeState runtimeState) { var trackingMessages = new List <BrokeredMessage>(); // We cannot create tracking messages if runtime state does not have Orchestration InstanceId // This situation can happen due to corruption of service bus session state or if somehow first message of orchestration is not execution started if (runtimeState == null || runtimeState.OrchestrationInstance == null || string.IsNullOrWhiteSpace(runtimeState.OrchestrationInstance.InstanceId)) { return(trackingMessages); } // this is to stamp the tracking events with a sequence number so they can be ordered even if // writing to a store like azure table int historyEventIndex = runtimeState.Events.Count - runtimeState.NewEvents.Count; foreach (HistoryEvent he in runtimeState.NewEvents) { var taskMessage = new TaskMessage { Event = he, OrchestrationInstance = runtimeState.OrchestrationInstance }; BrokeredMessage trackingMessage = Utils.GetBrokeredMessageFromObject( taskMessage, settings.MessageCompressionSettings, runtimeState.OrchestrationInstance, "History Tracking Message"); trackingMessage.ContentType = FrameworkConstants.TaskMessageContentType; trackingMessage.SessionId = runtimeState.OrchestrationInstance.InstanceId; trackingMessage.Properties[FrameworkConstants.HistoryEventIndexPropertyName] = historyEventIndex++; trackingMessages.Add(trackingMessage); } var stateMessage = new StateMessage { State = BuildOrchestrationState(runtimeState) }; BrokeredMessage brokeredStateMessage = Utils.GetBrokeredMessageFromObject( stateMessage, settings.MessageCompressionSettings, runtimeState.OrchestrationInstance, "State Tracking Message"); brokeredStateMessage.SessionId = runtimeState.OrchestrationInstance.InstanceId; brokeredStateMessage.ContentType = FrameworkConstants.StateMessageContentType; trackingMessages.Add(brokeredStateMessage); return(trackingMessages); }
protected override async Task OnProcessWorkItem(SessionWorkItem sessionWorkItem) { MessageSession session = sessionWorkItem.Session; IEnumerable <BrokeredMessage> newMessages = sessionWorkItem.Messages; var historyEntities = new List <OrchestrationHistoryEventEntity>(); var stateEntities = new List <OrchestrationStateEntity>(); foreach (BrokeredMessage message in newMessages) { Utils.CheckAndLogDeliveryCount(message, taskHubDescription.MaxTrackingDeliveryCount); if (message.ContentType.Equals(FrameworkConstants.TaskMessageContentType, StringComparison.OrdinalIgnoreCase)) { object historyEventIndexObj; if (!message.Properties.TryGetValue(FrameworkConstants.HistoryEventIndexPropertyName, out historyEventIndexObj) || historyEventIndexObj == null) { throw new InvalidOperationException( "Could not find a valid history event index property on tracking message " + message.MessageId); } var historyEventIndex = (int)historyEventIndexObj; TaskMessage taskMessage = await Utils.GetObjectFromBrokeredMessageAsync <TaskMessage>(message); historyEntities.Add(new OrchestrationHistoryEventEntity( taskMessage.OrchestrationInstance.InstanceId, taskMessage.OrchestrationInstance.ExecutionId, historyEventIndex, DateTime.UtcNow, taskMessage.Event)); } else if (message.ContentType.Equals(FrameworkConstants.StateMessageContentType, StringComparison.OrdinalIgnoreCase)) { StateMessage stateMessage = await Utils.GetObjectFromBrokeredMessageAsync <StateMessage>(message); stateEntities.Add(new OrchestrationStateEntity(stateMessage.State)); } else { throw new InvalidOperationException("Invalid tracking message content type: " + message.ContentType); } } TraceEntities(TraceEventType.Verbose, "Writing tracking history event", historyEntities, GetNormalizedHistoryEventEntityTrace); TraceEntities(TraceEventType.Verbose, "Writing tracking state event", stateEntities, GetNormalizedStateEntityTrace); try { await Utils.ExecuteWithRetries(() => tableClient.WriteEntitesAsync(historyEntities), session.SessionId, string.Format("WriteHistoryEntities:{0}", session.SessionId), MaxRetriesTableStore, IntervalBetweenRetriesSecs); } catch (Exception) { TraceEntities(TraceEventType.Critical, "Failed to write history entity", historyEntities, GetNormalizedHistoryEventEntityTrace); throw; } try { foreach (OrchestrationStateEntity stateEntity in stateEntities) { await Utils.ExecuteWithRetries( () => tableClient.WriteEntitesAsync(new List <OrchestrationStateEntity> { stateEntity }), session.SessionId, string.Format("WriteStateEntities:{0}", session.SessionId), MaxRetriesTableStore, IntervalBetweenRetriesSecs); } } catch (Exception) { TraceEntities(TraceEventType.Critical, "Failed to write state entity", stateEntities, GetNormalizedStateEntityTrace); throw; } IEnumerable <Guid> lockTokens = newMessages.Select(m => m.LockToken); Utils.SyncExecuteWithRetries <object>(() => { session.CompleteBatch(lockTokens); return(null); }, session.SessionId, "Complete New Tracking Messages", MaxRetriesServiceBus, IntervalBetweenRetriesSecs); }