public void StatusTest() { DateTime t1 = new DateTime(1950, 12, 1); // Stale heart beat is abandoned var entity = new InstanceTableEntity { RowKey = Guid.NewGuid().ToString(), StartTime = t1, FunctionInstanceHeartbeatExpiry = t1, // stale heartbeat }; var item = entity.ToFunctionLogItem(); Assert.Equal(FunctionInstanceStatus.Abandoned, item.GetStatus()); // recent heartbeat means running . entity.FunctionInstanceHeartbeatExpiry = DateTime.UtcNow.AddMinutes(2); item = entity.ToFunctionLogItem(); Assert.Equal(FunctionInstanceStatus.Running, item.GetStatus()); // endtime means complete entity.EndTime = DateTime.UtcNow; item = entity.ToFunctionLogItem(); Assert.Equal(FunctionInstanceStatus.CompletedSuccess, item.GetStatus()); }
public static async Task InitialMenu( [ActivityTrigger] ChatMessage chat, [Table("RunningInstances")] CloudTable table, ILogger log) { InstanceTableEntity session = new InstanceTableEntity { PartitionKey = chat.ChatId, RowKey = chat.InstanceId, ETag = "*" }; if (chat.MessageId.HasValue) { await DurableChatBot.botClient.DeleteMessageAsync(chat.ChatId, chat.MessageId.Value); } await table.ExecuteAsync(TableOperation.Delete(session)); await DurableChatBot.botClient.SendTextMessageAsync( chatId: chat.ChatId, text: "Your session timed out. You can create a new session for a new menu"); }
public static async Task <HttpResponseMessage> HttpStart( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req, [Table("RunningInstances")] CloudTable tableInput, [Table("RunningInstances")] IAsyncCollector <InstanceTableEntity> tableOutput, [OrchestrationClient] DurableOrchestrationClient starter, ILogger log) { string requestBody = await req.Content.ReadAsStringAsync(); try { Update update = JsonConvert.DeserializeObject <Update>(requestBody); string chatId = update.GetChatId(); TableQuery <InstanceTableEntity> sessionQuery = new TableQuery <InstanceTableEntity>().Where( TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, chatId)); TableQuerySegment <InstanceTableEntity> sessions = await tableInput.ExecuteQuerySegmentedAsync(sessionQuery, null); if ((update.Message?.Entities?.Length ?? 0) != 0 && (update.Message?.Entities?.First().Type ?? MessageEntityType.Unknown) == MessageEntityType.BotCommand && (update.Message?.EntityValues?.First()?.ToLowerInvariant().Equals("/cancel") ?? false)) { //Cancel current user session and reset all state! foreach (var entity in sessions) { await tableInput.ExecuteAsync(TableOperation.Delete(entity)); } await botClient.SendTextMessageAsync( chatId : chatId, text : $"All running ({sessions.Count()}) sessions have now been purged"); } else { bool didContinueASession = false; if (sessions.Count() > 0) { foreach (InstanceTableEntity session in sessions) { OrchestrationRuntimeStatus status = (await starter.GetStatusAsync(session.RowKey)).RuntimeStatus; if (status == OrchestrationRuntimeStatus.Failed || status == OrchestrationRuntimeStatus.Canceled || status == OrchestrationRuntimeStatus.Completed || status == OrchestrationRuntimeStatus.Terminated || status == OrchestrationRuntimeStatus.Unknown) { log.LogInformation($"Removing session with ID = '{session.RowKey}' because it was terminated"); await tableInput.ExecuteAsync(TableOperation.Delete(session)); await botClient.SendTextMessageAsync( chatId : chatId, text : $"FYI: I purged a old session with ID {session.RowKey} that had status: {status.ToString()} (Was started at UTC: {session.Timestamp.UtcDateTime.ToShortDateString()})"); } else { if (update.CallbackQuery != null) { //One should not have more than 1 running session, but I will not crash because of it. So just continue all the session until they get cleaned up. await starter.RaiseEventAsync(session.RowKey, "Callback", update); log.LogInformation($"Continuing on session with ID = '{session.RowKey}'"); didContinueASession = true; } } } } if (!didContinueASession) { var newInstance = new InstanceTableEntity { PartitionKey = chatId, RowKey = await starter.StartNewAsync("BotBrainFunction", update) }; await tableOutput.AddAsync(newInstance); log.LogInformation($"Started orchestration with ID = '{newInstance.RowKey}'."); } } } catch (Exception ex) { log.LogError(ex, $"Could not parse update data. {ex.Message}"); log.LogInformation(requestBody); } // Function input comes from the request content. //string instanceId = await starter.StartNewAsync("Function2", null); //log.LogInformation($"Started orchestration with ID = '{instanceId}'."); //return starter.CreateCheckStatusResponse(req, instanceId); HttpResponseMessage response = req.CreateResponse(HttpStatusCode.OK); //await Task.Delay(1); return(response); }