abpframework/abp · error · AbpException

Cannot convert period: {period} to cron expression, use Hang

Error message

Cannot convert period: {period} to cron expression, use HangfireBackgroundWorkerBase to define worker

What it means

Thrown by HangfireBackgroundWorkerManager.GetCron when converting a worker's Period (in milliseconds) to a cron expression and the period exceeds 31 days. The converter only supports ranges expressible in standard cron: seconds (<=59s), minutes, hours, and days up to 31. Periods longer than a month cannot be represented because cron has no 'every N months' field in this conversion logic.

Source

Thrown at framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs:185

        }
        else if (time.TotalMinutes <= 59)
        {
            var minutes = Math.Max(1, (int)Math.Round(time.TotalMinutes));
            cron = $"*/{minutes} * * * *";
        }
        else if (time.TotalHours <= 23)
        {
            var hours = Math.Max(1, (int)Math.Round(time.TotalHours));
            cron = $"0 */{hours} * * *";
        }
        else if(time.TotalDays <= 31)
        {
            var days = Math.Max(1, (int)Math.Round(time.TotalDays));
            cron = $"0 0 0 1/{days} * *";
        }
        else
        {
            throw new AbpException($"Cannot convert period: {period} to cron expression, use HangfireBackgroundWorkerBase to define worker");
        }

        return cron;
    }
}

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Reduce the Period to 31 days or less (<= 2,678,400,000 ms).
  2. For periods longer than a month, subclass HangfireBackgroundWorkerBase and set an explicit cron expression directly instead of relying on Period-to-cron conversion.
  3. If the large period was a unit mistake, correct the Period to the intended interval.

Example fix

// before — period exceeds 31 days
public class MonthlyReportWorker : AsyncPeriodicBackgroundWorkerBase
{
    public MonthlyReportWorker()
    {
        Period = (int)TimeSpan.FromDays(45).TotalMilliseconds; // throws
    }
}

// after — use HangfireBackgroundWorkerBase with explicit cron
public class MonthlyReportWorker : HangfireBackgroundWorkerBase
{
    public MonthlyReportWorker()
    {
        CronExpression = "0 0 1 * *"; // 1st of every month
    }
}
Defensive patterns

Strategy: validation

Validate before calling

int maxPeriodMs = (int)TimeSpan.FromDays(31).TotalMilliseconds;
if (worker.Period > maxPeriodMs)
{
    throw new InvalidOperationException($"Period {worker.Period} ms exceeds the 31-day cron limit. Use HangfireBackgroundWorkerBase with an explicit CronExpression.");
}

Type guard

static bool IsCronConvertiblePeriod(int periodMs) => TimeSpan.FromMilliseconds(periodMs).TotalDays <= 31;

Prevention

When it happens

Trigger: Setting an AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase Period to a value greater than 31 days (2,678,400,000 ms) while using the Hangfire background workers provider. The converter is invoked automatically when the worker is registered with HangfireBackgroundWorkerManager.

Common situations: Configuring a monthly or quarterly maintenance worker with Period = TimeSpan.FromDays(60). Setting a Period meant as seconds but accidentally as milliseconds, resulting in an enormous value (e.g. 60,000,000 ms ≈ 16 hours is fine, but 6,000,000,000 exceeds the limit).

Related errors


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