abpframework/abp · error · AbpException

The default in-memory background worker manager does not sup

Error message

The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz).

What it means

Thrown by DefaultDynamicBackgroundWorkerManager.AddAsync when the supplied DynamicBackgroundWorkerSchedule has a non-empty CronExpression. The default in-memory dynamic worker manager only supports Period-based scheduling (it uses an AbpAsyncTimer); it has no cron engine. The error tells you to drop CronExpression and use Period, or switch to Hangfire/Quartz which support cron.

Source

Thrown at framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs:47

        _dynamicWorkers = new ConcurrentDictionary<string, InMemoryDynamicBackgroundWorker>();
        _semaphore = new SemaphoreSlim(1, 1);
    }

    public virtual async Task AddAsync(
        string workerName,
        DynamicBackgroundWorkerSchedule schedule,
        DynamicBackgroundWorkerHandler handler,
        CancellationToken cancellationToken = default)
    {
        Check.NotNullOrWhiteSpace(workerName, nameof(workerName));
        Check.NotNull(schedule, nameof(schedule));
        Check.NotNull(handler, nameof(handler));

        schedule.Validate();

        if (!schedule.CronExpression.IsNullOrWhiteSpace())
        {
            throw new AbpException(
                $"The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. " +
                "Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz).");
        }

        await _semaphore.WaitAsync(cancellationToken);
        try
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(DefaultDynamicBackgroundWorkerManager));
            }

            if (_dynamicWorkers.TryRemove(workerName, out var existingWorker))
            {
                await existingWorker.StopAsync(cancellationToken);
                Logger.LogInformation("Replaced existing dynamic worker: {WorkerName}", workerName);
            }

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Clear CronExpression and set a Period (in ms) on the schedule: new DynamicBackgroundWorkerSchedule { Period = 60000 }.
  2. Add the Hangfire or Quartz background workers module to the project so the cron-capable dynamic manager resolves instead of the default.
  3. If you need both cron and the in-memory manager, reconsider — use a provider that supports cron.

Example fix

// before — cron expression with default in-memory manager (throws)
await dynamicManager.AddAsync("cron-worker",
    new DynamicBackgroundWorkerSchedule { CronExpression = "0 */5 * * *" },
    handler);

// after — use Period instead
await dynamicManager.AddAsync("periodic-worker",
    new DynamicBackgroundWorkerSchedule { Period = 300000 }, // 5 minutes
    handler);
Defensive patterns

Strategy: validation

Validate before calling

var schedule = new DynamicBackgroundWorkerSchedule { Period = 60000 };
if (!schedule.CronExpression.IsNullOrWhiteSpace() && dynamicManager is DefaultDynamicBackgroundWorkerManager)
{
    throw new NotSupportedException("Default in-memory manager does not support cron; clear CronExpression or use Hangfire/Quartz.");
}

Type guard

static bool ManagerSupportsCron(IDynamicBackgroundWorkerManager mgr) => mgr is not DefaultDynamicBackgroundWorkerManager;

Try / catch

try { await dynamicManager.AddAsync(name, schedule, handler, ct); }
catch (AbpException ex) when (ex.Message.Contains("does not support CronExpression"))
{
    logger.LogError(ex, "Clear CronExpression and use Period, or switch to Hangfire/Quartz.");
}

Prevention

When it happens

Trigger: Calling AddAsync on IDynamicBackgroundWorkerManager (resolved as DefaultDynamicBackgroundWorkerManager, the built-in implementation) with a DynamicBackgroundWorkerSchedule where CronExpression is set (e.g. "0 * * * *"). This happens when no Hangfire or Quartz background workers module is loaded, so the default in-memory manager is active.

Common situations: Developing with cron-based scheduling locally where the default manager is used (no Hangfire/Quartz dependency), then deploying the same schedule to production. Copying a schedule object that was built for Hangfire into a project without the Hangfire provider.

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/01bb308628b4f753. Report an issue: GitHub.