【发布时间】:2021-10-29 12:20:16
【问题描述】:
由于 Azure 内置负载均衡器上的 non-configurable 230-second timeout,我们在应用服务中有一个长时间运行的进程(可能需要超过 5 分钟)。
所以我们使用 Azure Durable Functions 重构为 async-http API pattern。由于超出本问题范围的原因,我们有一个单一的活动功能,不能轻易分解成更小的工作。
我注意到输出日志中有奇怪的结果,并确定活动函数在几分钟后被 Azure Functions重新启动。我在活动函数中设置了一个断点,几分钟后它(再次)被命中。
这不是我自己配置的;我启动函数的调用代码只执行一次。这是怎么回事?如何使活动功能运行完成?
当工作量少于几分钟时,它可以正常工作并按预期完成。
函数应用代码如下所示:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using OurContentModel;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Content20.Store
{
public class StoreContent
{
/// <summary>
/// Starter function called by HTTP. Starts the orchestrator and returns an endpoint the client
/// can query for status and for the result once complete.
/// </summary>
/// <remarks>See https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview?tabs=csharp#async-http </remarks>
[FunctionName("StoreContent")]
public async Task<IActionResult> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]
HttpRequest req,
[DurableClient] IDurableOrchestrationClient starter,
ILogger log)
{
// Get function input comes from the request content and query params.
// ...
var content = JsonConvert.DeserializeObject<OurData>(requestBody);
string instanceId = await starter.StartNewAsync(
"StoreContent_RunOrchestrator",
new StoreContentInputArgs()
{
OurContent = content
});
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
/// <summary>
/// Orchestration function that calls the activity function(s)
/// and returns the final result when they're done.
/// </summary>
[FunctionName("StoreContent_RunOrchestrator")]
public async Task<StoreContentResult> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var input = context.GetInput<StoreContentInputArgs>();
return await context.CallActivityAsync<StoreContentResult>("StoreContent_WriteFamilyData", input);
}
/// <summary>
/// Activity function that does the actual work.
/// </summary>
[FunctionName("StoreContent_WriteFamilyData")]
public async Task<StoreContentResult> WriteFamilyData([ActivityTrigger] StoreContentInputArgs input, ILogger log)
{
try
{
// breakpoint here gets hit a second time when first invocation takes more than a few minutes,
// with "external code" below it in the call stack so I assume it's getting (re)started by the system?
var storer = new OurContentStorer(log);
await storer.StoreContentAsync(input); // long-running process
return new StoreContentResult()
{
Success = true,
Message = "OK"
};
}
catch (Exception ex)
{
log.LogError(ex, ex.ToString());
return new StoreContentResult()
{
Success = false,
Message = ex.Message
};
}
}
}
}
我们已经在host.json 中将函数的超时时间增加到了一个小时。它在 Azure 的高级计划中运行。
当我在活动函数中设置中断时,调用堆栈在第二次命中断点时如下所示:
【问题讨论】:
标签: c# azure .net-core azure-functions azure-durable-functions