{"record":{"id":"63e6fa75475a729d","repo":"abpframework/abp","slug":"cannot-convert-period-period-to-cron-expression-63e6fa","errorCode":null,"errorMessage":"Cannot convert period: {period} to cron expression.","messagePattern":"Cannot convert period: (.+?) to cron expression\\.","errorType":"exception","errorClass":"AbpException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs","lineNumber":182,"sourceCode":"        }\n        else if (time.TotalMinutes <= 59)\n        {\n            var minutes = Math.Max(1, (int)Math.Round(time.TotalMinutes));\n            cron = $\"*/{minutes} * * * *\";\n        }\n        else if (time.TotalHours <= 23)\n        {\n            var hours = Math.Max(1, (int)Math.Round(time.TotalHours));\n            cron = $\"0 */{hours} * * *\";\n        }\n        else if (time.TotalDays <= 31)\n        {\n            var days = Math.Max(1, (int)Math.Round(time.TotalDays));\n            cron = $\"0 0 0 1/{days} * *\";\n        }\n        else\n        {\n            throw new AbpException($\"Cannot convert period: {period} to cron expression.\");\n        }\n\n        return cron;\n    }\n}\n","sourceCodeStart":164,"sourceCodeEnd":188,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs#L164-L188","documentation":"Thrown by HangfireDynamicBackgroundWorkerManager.GetCron when converting a dynamic worker's Period (milliseconds) to a cron expression and the period exceeds 31 days. Same conversion limitation as the static Hangfire manager: standard cron fields cannot express intervals longer than a month. This applies to dynamically registered workers scheduled by Period rather than cron.","triggerScenarios":"Calling AddAsync on the Hangfire dynamic background worker manager with a DynamicBackgroundWorkerSchedule whose Period (in ms) corresponds to more than 31 days. The GetCron converter is invoked because no CronExpression was supplied.","commonSituations":"Dynamically registering a long-running cleanup or archival worker with a multi-month Period. Passing a Period value that was meant in seconds but supplied in milliseconds, blowing past the 31-day ceiling.","solutions":["Reduce the Period to 31 days or fewer.","Provide a CronExpression in the DynamicBackgroundWorkerSchedule instead of a Period (e.g. \"0 0 1 * *\" for monthly), since Hangfire's dynamic manager supports cron expressions.","If the value is a unit error, correct the Period to the intended milliseconds."],"exampleFix":"// before — dynamic worker with a 60-day period\nawait dynamicManager.AddAsync(\"quarterly-cleanup\",\n    new DynamicBackgroundWorkerSchedule { Period = (int)TimeSpan.FromDays(60).TotalMilliseconds },\n    handler);\n\n// after — use a cron expression instead\nawait dynamicManager.AddAsync(\"quarterly-cleanup\",\n    new DynamicBackgroundWorkerSchedule { CronExpression = \"0 0 1 1,4,7,10 *\" },\n    handler);","handlingStrategy":"validation","validationCode":"var schedule = new DynamicBackgroundWorkerSchedule { Period = computedPeriod };\nif (schedule.Period.HasValue && TimeSpan.FromMilliseconds(schedule.Period.Value).TotalDays > 31)\n{\n    throw new InvalidOperationException(\"Period exceeds 31 days; set CronExpression instead for long intervals.\");\n}\nschedule.Validate();","typeGuard":"static bool IsCronConvertiblePeriod(int periodMs) => TimeSpan.FromMilliseconds(periodMs).TotalDays <= 31;","tryCatchPattern":null,"preventionTips":["For dynamic workers with intervals over 31 days, supply CronExpression instead of Period.","Wrap dynamic schedule creation in a helper that enforces the period ceiling.","Document which providers support cron and use them when long intervals are needed."],"tags":["hangfire","background-workers","dynamic-workers","cron","scheduling","period-conversion"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}