Skip to content

Instantly share code, notes, and snippets.

@alanta
Last active November 27, 2020 13:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanta/4b8cf669430fa6ee8e876ea016ba903e to your computer and use it in GitHub Desktop.
Save alanta/4b8cf669430fa6ee8e876ea016ba903e to your computer and use it in GitHub Desktop.
Singleton eternal function with watchdog timer
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DurableFunctionsPatterns
{
public class EternalFunctionWithWatchdogTimer
{
private const string FunctionName = "EternalFunctionWithWatchdogTimer";
private const string UniqueInstanceId = "MyBackgroundProcess";
private const string EveryMinute = "0 */1 * * * *";
private readonly ILogger<Orchestrator> _logger;
public EternalFunctionWithWatchdogTimer(ILogger<Orchestrator> logger)
{
_logger = logger;
}
[FunctionName(FunctionName+"_WatchdogTimer")]
public async Task TimerStart(
[TimerTrigger(EveryMinute, RunOnStartup = true)]
TimerInfo timer,
[DurableClient] IDurableOrchestrationClient starter)
{
await EnsureRunning(starter);
}
private async Task EnsureRunning(IDurableOrchestrationClient starter)
{
// Check if an instance with the specified ID already exists or an existing one stopped running(completed/failed/terminated).
var existingInstance = await starter.GetStatusAsync(UniqueInstanceId);
if (existingInstance == null
|| existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Completed
|| existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Failed
|| existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Terminated)
{
var startedInstance = await starter.StartNewAsync(FunctionName, instanceId: UniqueInstanceId);
_logger.LogInformation("Started orchestration {instance}'.", UniqueInstanceId);
}
else
{
_logger.LogDebug($"Orchestration {UniqueInstanceId} is running.");
}
}
private Random random = new Random(DateTime.UtcNow.Millisecond);
[FunctionName(FunctionName)]
public async Task RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
_logger.LogInformation($"Do stuff {context.InstanceId}");
if (random.Next(10) > 7)
{
throw new InvalidOperationException("Random exception that terminates the orchestrator");
}
// sleep for a while
DateTime nextCleanup = context.CurrentUtcDateTime.AddSeconds(20);
await context.CreateTimer(nextCleanup, CancellationToken.None);
_logger.LogInformation($"Wake up {context.InstanceId}");
context.ContinueAsNew(null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment