我正在一个基于无服务器计时器的持久函数中工作,但一直得到错误:
[2022-10-11T03:42:06.874Z] ServerlessTimers.Application: Exception of type 'System.Exception' was thrown.
[2022-10-11T03:42:06.883Z] 0396b0bd-6a87-4490-a2fe-b0b9121a9504: Function 'OrchestrateTimerFunction (Orchestrator)' failed with an error. Reason: System.InvalidOperationException: Multithreaded execution was detected. This can happen if the orchestrator function code awaits on a task that was not created by a DurableOrchestrationContext method. More details can be found in this article https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-checkpointing-and-replay#orchestrator-code-constraints.
[2022-10-11T03:42:06.886Z] at Microsoft.Azure.WebJobs.Extensions.DurableTask.DurableOrchestrationContext.ThrowIfInvalidAccess() in D:\a\_work\1\s\src\WebJobs.Extensions.DurableTask\ContextImplementations\DurableOrchestrationContext.cs:line 1163
[2022-10-11T03:42:06.887Z] at Microsoft.Azure.WebJobs.Extensions.DurableTask.TaskOrchestrationShim.InvokeUserCodeAndHandleResults(RegisteredFunctionInfo orchestratorInfo, OrchestrationContext innerContext) in D:\a\_work\1\s\src\WebJobs.Extensions.DurableTask\Listener\TaskOrchestrationShim.cs:line 150. IsReplay: False. State: Failed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.7.1. SequenceNumber: 4. TaskEventId: -1
从我的Angular 来看,我看不出该编排器函数有什么问题。有趣的是,当我在该编排器函数中设置断点并调用该函数时,错误消失了,日志中看不到任何错误。这是否意味着它可能是关于调用该编排器的http-triggerd函数的争用条件?似乎极不可能,但如果我错了,请纠正我。
这里是配器功能。这个“计时器”和你手机上的一样,只是在云端。
namespace ServerlessTimers.Application.Functions.Durables;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.Logging;
using ServerlessTimers.Application.Exceptions;
using ServerlessTimers.Application.Models.DurableEvents;
using ServerlessTimers.Application.Models.Durables;
using ServerlessTimers.Application.Services.Durables;
using ServerlessTimers.Domain.Aggregators.Timers;
using ServerlessTimers.Domain.Services;
public class OrchestrateTimerFunction
{
private readonly ILogger logger;
private readonly IDurableFacade durableFacade;
private readonly ITimerRepository timerRepository;
private readonly ITimerCalculatorFactory calculatorFactory;
private readonly CancellationTokenSource cts;
public OrchestrateTimerFunction(
IDurableFacade durableFacade,
ITimerRepository timerRepository,
ITimerCalculatorFactory calculatorFactory,
ILogger<OrchestrateTimerFunction> logger)
{
this.logger = logger;
this.durableFacade = durableFacade;
this.timerRepository = timerRepository;
this.calculatorFactory = calculatorFactory;
cts = new CancellationTokenSource();
}
[FunctionName(nameof(OrchestrateTimerFunction))]
public async Task RunOrchestrator(
[OrchestrationTrigger]
IDurableOrchestrationContext context)
{
try
{
// Get timer
var input = context.GetInput<TimerOrchestratorInput>();
var timer = await timerRepository.FindByIdAsync(input.TimerId) ??
throw new TimerNotFoundException(input.TimerId);
// Do not run orchestration if timer's shouldn't be running
if(!timer.State.EqualRunningState())
{
logger.LogError($"Timer {timer.Id}: " +
$"Tried to be orchestrated but has {timer.State} state");
throw new Exception();
}
// Calculate the completion date of the timer
var calculator = calculatorFactory.GetCalculator(timer);
var remainingTime = calculator.CalculateRemainingTime();
logger.LogInformation($"Timer {timer.Id}: " +
$"To complete in {remainingTime}");
if (remainingTime <= TimeSpan.Zero)
{
logger.LogError($"Timer {timer.Id}: " +
$"Remaining time is negative");
throw new Exception();
}
// Set external events
var timerPausedEventTask = context.WaitForExternalEvent<DurableEvent>(
name: nameof(TimerPausedDurableEvent),
defaultValue: new TimerCompletedDurableEvent(),
timeout: remainingTime,
cancelToken: cts.Token);
var timerStoppedEventTask = context.WaitForExternalEvent<DurableEvent>(
name: nameof(TimerStoppedDurableEvent),
defaultValue: new TimerCompletedDurableEvent(),
timeout: remainingTime,
cancelToken: cts.Token);
// Await timer
var durableEvent = await Task.WhenAny<DurableEvent>(
timerPausedEventTask, timerStoppedEventTask);
cts.Cancel();
// Handle events
if(durableEvent.Result is TimerCompletedDurableEvent)
{
logger.LogInformation($"Timer {timer.Id}: Completed");
}
else if (durableEvent.Result is TimerStoppedDurableEvent)
{
logger.LogInformation($"Timer {timer.Id}: Stopped");
}
else if (durableEvent.Result is TimerPausedDurableEvent pausedEvent)
{
logger.LogInformation($"Timer {timer.Id}: Paused ({pausedEvent.Reason})");
}
}
catch(Exception ex)
{
logger.LogError(ex, ex.Message);
}
}
}
1条答案
按热度按时间2vuwiymt1#
您的代码可能超出了编排器工作所需的code constraints。您应该将此类代码移到活动函数中以使其工作。
在你的例子中,我会说下面几行是原因,因为在重放时,它们可能会产生不同的结果。
1、
二、
三、