azuremulti-tenantautoscalingquartz.netazure-durable-functions

How Can I Ensure Quartz.NET Scheduling Compatibility in a Multi-tenant Azure Application Before Enabling Auto-Scaling?


I am working on a project that utilizes Quartz.NET for scheduling data pulls within a multi-tenant Azure environment. We are considering enabling auto-scaling and want to ensure that Quartz.NET is compatible and will operate efficiently under these conditions.

Is Quartz.NET auto-scalable, or does it require integration with Azure Functions for scalability? If unchanged, will a data pull occur for each instance upon scaling? How will scaling up or down affect this? Would transitioning to an Azure Function be more suitable for handling scheduled tasks in a scalable environment? Any insights or experiences on handling Quartz.NET scheduling in potential auto-scale Azure environments would be greatly appreciated. Thank you!

Editing to hopefully make the question more specific. Here is a very simplified example of code we wish to make sure will scale correctly. This job, goes over every tenant and for each of them dispatches reminders in the form of email when the reminder is due.

public class TuRemindersJob : IJob
{
    private readonly IServiceProvider _serviceProvider;

    private readonly ILogger<TuRemindersJob> _logger;

    public TuRemindersJob(IServiceProvider serviceProvider, ILogger<TuRemindersJob> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        var correlationId = Guid.NewGuid().ToString("N");

        using var outerScope = _serviceProvider.CreateScope();
        var tenantDataProvider = outerScope.ServiceProvider.GetRequiredService<ITenantDataProvider>();

        var allTenants = tenantDataProvider.GetAllTenants()
            .Select(x => new TenantDto(x.TenantId, x.TenantName));

        foreach (var tenant in allTenants)
        {
            using var innerScope = outerScope.ServiceProvider.CreateScope();
            var claimsInitializer = innerScope.ServiceProvider.GetRequiredService<IClaimsInitializer>();
            claimsInitializer.InitializeAsMachine(tenant.Id, correlationId);

            var sendTuRemindersJob = innerScope.ServiceProvider.GetRequiredService<ISendTuRemindersCommand>();
            // This command goes over db to check for scheduled alerts, if due for a user then sends them an email
            var sendTuRemindersResponse = await sendTuRemindersJob.ExecuteAsync(DateTime.UtcNow, CancellationToken.None);

            if (sendTuRemindersResponse.IsSuccess)
            {
                continue;
            }
        }
    }
}

If run in an autoscale environment that scales at minimum for 3 to 10 instances, will the users be sent an email for every instance? Can we modify these types of solutions using Quartz easily to work in an autoscale environment, or should these be extracted into azure functions?


Solution

  • Think of a scaled-out Azure app service as multiple servers that sit behind a load balancer and don't know about each other. So effectively it's a cluster of servers and if you want to run Quartz.NET jobs on an app service with multiple instances, each of the instances will be trying to run jobs at the same time. In your example, each instance will attempt to send an email reminder. Depending on functionality you want to run as scheduled jobs and how it's implemented, there could be other problems with scaled-out app services such as race conditions and potential data corruption.

    Quartz.NET can work in a load-balanced mode when multiple servers are connected to the same job store and clustering feature is enabled. All servers in the cluster will share the same configuration, time triggers will fire on each of them but only the first server will lock a job for execution to prevent other servers from running it. Please refer to Quatz.NET clustering documentation for configuration details and pay attention to the warnings as there are some edge cases and data corruption is still possible.

    For solutions hosted in Azure PaaS I would still recommend using Azure Functions or WebJobs. Azure Functions is usually the best choice as they offer more flexible scaling and do not depend on the app service plan of your web application. There are scenarios when WebJobs work better though, check the documentation here to see if these cases are relevant to your application.