I wanted to upgrade our project to the new version (8.2.0 from 8.1) but then I encountered this problem when starting the application, the problem seems to be that the way jobs/workers id are registered is not correct anymore since of a limit to hangfire Ids i guess. The workers that causes the problem are the ones generated by ABP, specifically HangfirePeriodicBackgroundWorkerAdapter<BackgroundJobWorker>.DoWorkAsync and HangfirePeriodicBackgroundWorkerAdapter<TokenCleanupBackgroundWorker>.DoWorkAsync.
I had to override AddAsync of HangfireBackgroundWorkerManager ( still had to find a better way of handling ids ) also i hade to modify logic a bit since it was filled with obsolete methods of hangfire
//public override async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default) //{ // switch (worker) // { // case IHangfireBackgroundWorker hangfireBackgroundWorker: // { // var unProxyWorker = ProxyHelper.UnProxy(hangfireBackgroundWorker);
// var jobId = string.IsNullOrEmpty(hangfireBackgroundWorker.RecurringJobId) ? hangfireBackgroundWorker.GetType().Name : hangfireBackgroundWorker.RecurringJobId; // var timezone = hangfireBackgroundWorker.TimeZone ?? TimeZoneInfo.Utc;
// RecurringJob.AddOrUpdate( // jobId, // hangfireBackgroundWorker.Queue, // () => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(cancellationToken), // hangfireBackgroundWorker.CronExpression, // new RecurringJobOptions // { // TimeZone = timezone // } // );
// break; // } // case AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase: // { // var timer = worker.GetType() // .GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker);
// var period = worker is AsyncPeriodicBackgroundWorkerBase ? ((AbpAsyncTimer?)timer)?.Period : ((AbpTimer?)timer)?.Period;
// if (period == null) // { // return; // }
// var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); // var workerAdapter = (Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker)!;
// var jobId = string.IsNullOrEmpty(workerAdapter.RecurringJobId) ? workerAdapter.GetType().Name : workerAdapter.RecurringJobId; // var timezone = workerAdapter.TimeZone ?? TimeZoneInfo.Utc;
// RecurringJob.AddOrUpdate( // jobId, // workerAdapter.Queue, // () => workerAdapter.DoWorkAsync(cancellationToken), // GetCron(period.Value), // new RecurringJobOptions // { // TimeZone = timezone // } // ); // break; // } // default: // await base.AddAsync(worker, cancellationToken); // break; // }
//}
the below image shows the ids generated by abp ( they work in abp 8.1)
here are the versions i use for hangfire/background workers
- ABP Framework version: v8.2.0
- UI Type: Angular
- Database System: EF Core (SQL Server )
- Exception message and full stack trace:
[14:40:24 FTL] Host terminated unexpectedly!
Volo.Abp.AbpInitializationException: An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Volo.Abp.Identity.AbpIdentityProDomainModule, Volo.Abp.Identity.Pro.Domain, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null: String or binary data would be truncated in table 'sqldb-qq-dev.HangFire.Hash', column 'Key'. Truncated value: 'recurring-job:HangfirePeriodicBackgroundWorkerAdapter<IdentitySessionCleanupBackgroundWorker>.DoWork'.. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): String or binary data would be truncated in table 'sqldb-qq-dev.HangFire.Hash', column 'Key'. Truncated value: 'recurring-job:HangfirePeriodicBackgroundWorkerAdapter<IdentitySessionCleanupBackgroundWorker>.DoWork'.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method) at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource
1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Hangfire.SqlServer.SqlCommandBatch.ExecuteNonQuery() in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlCommandBatch.cs:line 122
at Hangfire.SqlServer.SqlServerWriteOnlyTransaction.<Commit>b__17_0(DbConnection connection, DbTransaction transaction) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerWriteOnlyTransaction.cs:line 100
at Hangfire.SqlServer.SqlServerStorage.<>c__DisplayClass41_0.<UseTransaction>b__0(DbConnection connection, DbTransaction transaction) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerStorage.cs:line 272
at Hangfire.SqlServer.SqlServerStorage.<>c__DisplayClass42_01.<UseTransaction>b__0(DbConnection connection) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerStorage.cs:line 319 at Hangfire.SqlServer.SqlServerStorage.UseConnection[T](DbConnection dedicatedConnection, Func
2 func) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerStorage.cs:line 257
at Hangfire.SqlServer.SqlServerStorage.UseTransaction[T](DbConnection dedicatedConnection, Func3 func, Nullable
1 isolationLevel) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerStorage.cs:line 307
at Hangfire.SqlServer.SqlServerStorage.UseTransaction(DbConnection dedicatedConnection, Action2 action) in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerStorage.cs:line 270 at Hangfire.SqlServer.SqlServerWriteOnlyTransaction.Commit() in C:\projects\hangfire-525\src\Hangfire.SqlServer\SqlServerWriteOnlyTransaction.cs:line 69 at Hangfire.RecurringJobManager.AddOrUpdate(String recurringJobId, Job job, String cronExpression, RecurringJobOptions options) in C:\projects\hangfire-525\src\Hangfire.Core\RecurringJobManager.cs:line 148 at Hangfire.RecurringJobManagerExtensions.AddOrUpdate(IRecurringJobManager manager, String recurringJobId, Job job, String cronExpression, TimeZoneInfo timeZone, String queue) in C:\projects\hangfire-525\src\Hangfire.Core\RecurringJobManagerExtensions.cs:line 65 at Hangfire.RecurringJob.AddOrUpdate(Expression
1 methodCall, String cronExpression, TimeZoneInfo timeZone, String queue) in C:\projects\hangfire-525\src\Hangfire.Core\RecurringJob.cs:line 379
at Volo.Abp.BackgroundWorkers.Hangfire.HangfireBackgroundWorkerManager.AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken)
at Volo.Abp.Identity.AbpIdentityProDomainModule.OnApplicationInitializationAsync(ApplicationInitializationContext context)
at Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor.InitializeAsync(ApplicationInitializationContext context, IAbpModule module)
at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context)
ClientConnectionId:10a70a4f-4051-4c9b-bcde-e5e0c47734c6
Error Number:2628,State:1,Class:16
--- End of inner exception stack trace ---
at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context)
at Volo.Abp.AbpApplicationBase.InitializeModulesAsync()
at Volo.Abp.AbpApplicationWithExternalServiceProvider.InitializeAsync(IServiceProvider serviceProvider)
at Microsoft.AspNetCore.Builder.AbpApplicationBuilderExtensions.InitializeApplicationAsync(IApplicationBuilder app)
at Jeremias.QQ.Program.Main(String[] args) in C:\Users\AndreiIonutPislaru\source\repos\src\Jeremias.QQ.HttpApi.Host\Program.cs:line 64
3 Answer(s)
-
0
https://github.com/abpframework/abp/commits/b9ae57b38bbfe29837079be54bfab31b9949b55a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
The main logic has not changed in a year.
This is not ABP problem, but Hangfire. you can try to change the field length
-
0
https://github.com/abpframework/abp/commits/b9ae57b38bbfe29837079be54bfab31b9949b55a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
The main logic has not changed in a year.
This is not ABP problem, but Hangfire. you can try to change the field length
can you test with the versions i gave you in the screenshot?
-
0
Hi,
I will fix it in the next patch version. You can try this
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(IBackgroundWorkerManager), typeof(HangfireBackgroundWorkerManager))] public class MyHangfireBackgroundWorkerManager : HangfireBackgroundWorkerManager { public MyHangfireBackgroundWorkerManager(IServiceProvider serviceProvider) : base(serviceProvider) { } public override async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default) { switch (worker) { case IHangfireBackgroundWorker hangfireBackgroundWorker: { var unProxyWorker = ProxyHelper.UnProxy(hangfireBackgroundWorker); if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace()) { RecurringJob.AddOrUpdate( () => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(cancellationToken), hangfireBackgroundWorker.CronExpression, hangfireBackgroundWorker.TimeZone, hangfireBackgroundWorker.Queue); } else { RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId, () => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(cancellationToken), hangfireBackgroundWorker.CronExpression, hangfireBackgroundWorker.TimeZone, hangfireBackgroundWorker.Queue); } break; } case AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase: { var timer = worker.GetType() .GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); var period = worker is AsyncPeriodicBackgroundWorkerBase ? ((AbpAsyncTimer?)timer)?.Period : ((AbpTimer?)timer)?.Period; if (period == null) { return; } var unProxiedType = ProxyHelper.GetUnProxiedType(worker); var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(unProxiedType); var workerAdapter = (Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker)!; RecurringJob.AddOrUpdate(unProxiedType.Name, () => workerAdapter.DoWorkAsync(cancellationToken), GetCron(period.Value), workerAdapter.TimeZone, workerAdapter.Queue); break; } default: await base.AddAsync(worker, cancellationToken); break; } } protected override string GetCron(int period) { var time = TimeSpan.FromMilliseconds(period); string cron; if (time.TotalSeconds <= 59) { cron = $"*/{time.TotalSeconds} * * * * *"; } else if (time.TotalMinutes <= 59) { cron = $"*/{time.TotalMinutes} * * * *"; } else if (time.TotalHours <= 23) { cron = $"0 */{time.TotalHours} * * *"; } else if(time.TotalDays <= 31) { cron = $"0 0 0 1/{time.TotalDays} * *"; } else { throw new AbpException( $"Cannot convert period: {period} to cron expression, use HangfireBackgroundWorkerBase to define worker"); } return cron; } }