We are using MultiTenancy. When I created scheduled job and it was executed it doesn't work as expected. It doesn't have the correct context - TenantId is null. But when I was calling job Tenat was not null. Does it mean that hangfire jobs doesn't work with multiTenancy. Or if you can suggest some approach please write.
- ABP Framework version: vX.X.X
- UI Type: Angular
- Database System: EF Core ( PostgreSQL, etc..)
-
- Auth Server Separated (for Angular)**: yes
- Exception message and full stack trace:
- Steps to reproduce the issue:
4 Answer(s)
-
0
hi
When I created scheduled job and it was executed it doesn't work as expected. It doesn't have the correct context - TenantId is null.
Please share your code.
Thanks
-
0
public class AssessmentJobsService : DomainService, IAssessmentJobsService { #region Fields private readonly IAssessmentDetailRepository _assessmentDetailRepository; private readonly IMediaRepository _mediaRepository; private readonly IBlobManager _blobManager; private readonly IAssessmentRepository _assessmentRepository; #endregion #region Constructors /// <summary> /// Initializes a new instance of the <see cref="AssessmentJobsService" /> class. /// </summary> /// <param name="assessmentDetailRepository">The assessment repository.</param> /// <param name="mediaRepository">The media repository.</param> /// <param name="blobManager">The blob manager.</param> public AssessmentJobsService( IAssessmentDetailRepository assessmentDetailRepository, IMediaRepository mediaRepository, IBlobManager blobManager, IAssessmentRepository assessmentRepository) { _assessmentDetailRepository = assessmentDetailRepository; _mediaRepository = mediaRepository; _blobManager = blobManager; _assessmentRepository = assessmentRepository; } #endregion /// <inheritdoc/> public void SheduleAssessmentCleanup(long assessmentId) { BackgroundJob.Schedule(() => CleanUpAssessment(assessmentId), TimeSpan.FromSeconds(30)); } public void SheduleEmptyAssessmentCleanup(long assessmentId) { BackgroundJob.Schedule(() => CleanUpEmptyAssessment(assessmentId), TimeSpan.FromHours(4)); } /// <inheritdoc/> public void SheduleMediaCleanup(long mediaId) { BackgroundJob.Schedule(() => CleanUpMedia(mediaId), TimeSpan.FromHours(4)); } /// <inheritdoc/> public async Task StartTrackingJob(long assessmentDetailId, bool isOneStepProcess) { // Create a Hangfire job to finish the job if not all methods are called within 5 minutes var jobId = BackgroundJob.Schedule(() => CheckProcessVideoTracking(assessmentDetailId, isOneStepProcess), TimeSpan.FromMinutes(3)); var assessementDetails = await _assessmentDetailRepository.GetAsync(assessmentDetailId); assessementDetails.JobId = jobId; // Sets default status assessementDetails.ProcessVideoTrackStatus = (int)ProcessVideoTrackingStatus.InProgress; assessementDetails.ProcessVideoTrackStatusValue = ProcessVideoTrackingStatus.InProgress.ToString(); await _assessmentDetailRepository.UpdateAsync(assessementDetails, true); } /// <inheritdoc/> //[AutomaticRetry(Attempts = 5, DelaysInSeconds = new[] { 300, 600, 900, 1800, 3600 })] [AutomaticRetry(Attempts = 5, DelaysInSeconds = new[] { 60, 60, 60 })] public async Task CheckProcessVideoTracking(long assessmentDetailId, bool isOneStepProcess) { var assessmentDetails = await _assessmentDetailRepository.GetAsync(assessmentDetailId) ?? throw new Exception($"Job failed. Assessment details were not found"); var status = (ProcessVideoTrackingStatus)assessmentDetails.ProcessVideoTrackStatus; if ((isOneStepProcess && status == ProcessVideoTrackingStatus.ProcessData) || (!isOneStepProcess && status == (ProcessVideoTrackingStatus.ProcessData | ProcessVideoTrackingStatus.Report | ProcessVideoTrackingStatus.Overlay))) { return; } throw new Exception($"Job failed. Status {status}"); } /// <inheritdoc/> public async Task CleanUpMedia(long mediaId) { var mediaIsInUse = await _mediaRepository.CheckMediaWithAssessmentDetails(mediaId); if (!mediaIsInUse) { var media = await _mediaRepository.FindAsync(mediaId); if(media == null) { return; } await _mediaRepository.DeleteAsync(mediaId); await _blobManager.DeleteBlob(media?.MediaUrl, media?.FileName); } } /// <inheritdoc/> public async Task CleanUpMediaMedBridge() { try { // Get details from assessment where externalAssessmentId != null var mediaIds = await _assessmentDetailRepository.GetListMediaIdAndCleanDetailsMedbridgeAsync(); if (mediaIds != null) { var mediaQueryable = await _mediaRepository.GetQueryableAsync(); var medias = mediaQueryable.Where(m => mediaIds.Contains(m.Id)).ToList(); if (medias == null) { return; } await _mediaRepository.DeleteManyAsync(mediaIds, true); foreach (var media in medias) { await _blobManager.DeleteBlob(media?.MediaUrl, media?.FileName); } } } catch (Exception ex) { throw new Exception(ex.Message); } } /// <inheritdoc/> public async Task CleanUpAssessment(long assessmentId) { var details = await _assessmentDetailRepository.GetListAsync(x => x.AssessmentId == assessmentId); var mediaIds = details.Select(x => x.MediaId).ToList(); await _assessmentDetailRepository.DeleteManyAsync(details); var medias = await _mediaRepository.GetListAsync(x => mediaIds.Contains(x.Id)); await _mediaRepository.DeleteManyAsync(medias); foreach (var media in medias) { await _blobManager.DeleteBlob(media.MediaUrl, media.FileName); } } public async Task CleanUpEmptyAssessment(long assessmentId) { if (!await _assessmentDetailRepository.CheckAssessmentWithAssessmentDetails(assessmentId)) { var assessment = await _assessmentRepository.FindAsync(assessmentId); if (assessment != null) { await _assessmentRepository.DeleteAsync(assessment); } } } }
and in HttpHostModule
private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddHangfire(config => { GlobalConfiguration.Configuration.UsePostgreSqlStorage(configuration.GetConnectionString("Default")); }); }
-
0
And one moment I use API and we have API-Key authentication.
-
0
hi
You can add a
tenantid
parameter to the methods.BackgroundJob.Schedule(() => CleanUpMediaMedBridge(tenantid), TimeSpan.FromHours(4));
public async Task CleanUpMediaMedBridge(Guid? tenantid) { //https://docs.abp.io/en/abp/latest/Multi-Tenancy#change-the-current-tenant }
The
CleanUpMediaMedBridge
method is called by hangfire. So it will lose all context.