diff --git a/RMuseum/Controllers/GanjoorController.cs b/RMuseum/Controllers/GanjoorController.cs
index 204dfd84..6e8dbb16 100644
--- a/RMuseum/Controllers/GanjoorController.cs
+++ b/RMuseum/Controllers/GanjoorController.cs
@@ -4529,6 +4529,7 @@ namespace RMuseum.Controllers
/// category page, overwriting their stored TajikHtmlText. Needed one-time after changing
/// either generator function (e.g. adding poem excerpts to the table of contents), since
/// the normal SQLite import skips pages that already exist and never refreshes them.
+ /// Runs as a background job - check the Admin area's LongRunningJobs page for progress.
///
///
[HttpPut]
@@ -4536,10 +4537,10 @@ namespace RMuseum.Controllers
[Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)]
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))]
[ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))]
- public async Task RegenerateTajikCatAndPoetHtmlTextAsync()
+ public IActionResult RegenerateTajikCatAndPoetHtmlTextAsync()
{
RServiceResult res =
- await _ganjoorService.RegenerateTajikCatAndPoetHtmlTextAsync();
+ _ganjoorService.RegenerateTajikCatAndPoetHtmlTextAsync();
if (res.Result)
return Ok();
return BadRequest(res.ExceptionString);
diff --git a/RMuseum/Services/IGanjoorService.cs b/RMuseum/Services/IGanjoorService.cs
index 125ffa73..cb02fe54 100644
--- a/RMuseum/Services/IGanjoorService.cs
+++ b/RMuseum/Services/IGanjoorService.cs
@@ -1585,10 +1585,11 @@ namespace RMuseum.Services
///
/// re-runs the Tajik poet/category HTML generators for every already-imported poet and
/// category page, overwriting their stored TajikHtmlText - needed one-time after changing
- /// either generator function, since the normal SQLite import skips pages that already exist
+ /// either generator function, since the normal SQLite import skips pages that already exist.
+ /// Runs as a background job; returns immediately once the job is queued.
///
///
- Task> RegenerateTajikCatAndPoetHtmlTextAsync();
+ RServiceResult RegenerateTajikCatAndPoetHtmlTextAsync();
diff --git a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Tajik.cs b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Tajik.cs
index 59ed48e8..a9ac2f38 100644
--- a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Tajik.cs
+++ b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Tajik.cs
@@ -7,6 +7,7 @@ using RMuseum.Models.Ganjoor.ViewModels;
using System.Linq;
using RSecurityBackend.Services.Implementation;
using System.Collections.Generic;
+using RMuseum.DbContext;
namespace RMuseum.Services.Implementation
{
@@ -207,43 +208,77 @@ namespace RMuseum.Services.Implementation
}
///
- /// re-runs PrepareTajikPoetHtmlTextAsync / PrepareTajikCatHtmlTextAsync for every poet and
- /// category page that already has a stored TajikPages row, overwriting TajikHtmlText with
- /// freshly generated output. Needed one-time after changing either generator function
- /// (e.g. adding poem excerpts to the table of contents), because the normal SQLite import
- /// (GanjoorService-TajikSQLiteImport.cs) explicitly skips pages that already exist and so
- /// never refreshes previously generated HTML on its own.
+ /// re-runs the Tajik poet/category HTML generators for every already-imported poet and
+ /// category page, overwriting their stored TajikHtmlText. Needed one-time after changing
+ /// either generator function (e.g. adding poem excerpts to the table of contents), since
+ /// the normal SQLite import skips pages that already exist and never refreshes them.
+ /// Runs as a background job (same pattern as TajikImportFromSqlite) since the number of
+ /// poets/categories/poems involved can be large enough to exceed a normal request timeout;
+ /// progress can be tracked the same way as other long running jobs (e.g. the Admin area's
+ /// LongRunningJobs page).
///
- public async Task> RegenerateTajikCatAndPoetHtmlTextAsync()
+ public RServiceResult RegenerateTajikCatAndPoetHtmlTextAsync()
{
try
{
- var tajikPoets = await _context.TajikPoets.AsNoTracking().ToListAsync();
- foreach (var tajikPoet in tajikPoets)
- {
- var poetPage = await _context.GanjoorPages.AsNoTracking().Where(p => p.GanjoorPageType == GanjoorPageType.PoetPage && p.PoetId == tajikPoet.Id).SingleOrDefaultAsync();
- if (poetPage == null) continue;
- var tajikPage = await _context.TajikPages.Where(p => p.Id == poetPage.Id).SingleOrDefaultAsync();
- if (tajikPage == null) continue;
- tajikPage.TajikHtmlText = await PrepareTajikPoetHtmlTextAsync(_context, tajikPoet);
- }
- await _context.SaveChangesAsync();
+ _backgroundTaskQueue.QueueBackgroundWorkItem
+ (
+ async token =>
+ {
+ using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC
+ {
+ LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context);
+ var job = (await jobProgressServiceEF.NewJob("RegenerateTajikCatAndPoetHtmlText", "Query data")).Result;
- var tajikCats = await _context.TajikCats.AsNoTracking().ToListAsync();
- foreach (var tajikCat in tajikCats)
- {
- var tajikPage = await _context.TajikPages.Where(p => p.Id == tajikCat.Id).SingleOrDefaultAsync();
- if (tajikPage == null) continue;
- tajikPage.TajikHtmlText = await PrepareTajikCatHtmlTextAsync(_context, tajikCat);
- }
- await _context.SaveChangesAsync();
+ try
+ {
+ var tajikPoets = await context.TajikPoets.AsNoTracking().ToListAsync();
+ int done = 0;
+ foreach (var tajikPoet in tajikPoets)
+ {
+ await jobProgressServiceEF.UpdateJob(job.Id, done, $"poet: {tajikPoet.Id}");
+ var poetPage = await context.GanjoorPages.AsNoTracking().Where(p => p.GanjoorPageType == GanjoorPageType.PoetPage && p.PoetId == tajikPoet.Id).SingleOrDefaultAsync();
+ if (poetPage != null)
+ {
+ var tajikPage = await context.TajikPages.Where(p => p.Id == poetPage.Id).SingleOrDefaultAsync();
+ if (tajikPage != null)
+ {
+ tajikPage.TajikHtmlText = await PrepareTajikPoetHtmlTextAsync(context, tajikPoet);
+ await context.SaveChangesAsync();
+ }
+ }
+ done++;
+ }
- return new RServiceResult(true);
+ var tajikCats = await context.TajikCats.AsNoTracking().ToListAsync();
+ done = 0;
+ foreach (var tajikCat in tajikCats)
+ {
+ await jobProgressServiceEF.UpdateJob(job.Id, done, $"cat: {tajikCat.Id}");
+ var tajikPage = await context.TajikPages.Where(p => p.Id == tajikCat.Id).SingleOrDefaultAsync();
+ if (tajikPage != null)
+ {
+ tajikPage.TajikHtmlText = await PrepareTajikCatHtmlTextAsync(context, tajikCat);
+ await context.SaveChangesAsync();
+ }
+ done++;
+ }
+
+ await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true);
+ }
+ catch (Exception exp)
+ {
+ await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString());
+ }
+ }
+ }
+ );
}
catch (Exception exp)
{
return new RServiceResult(false, exp.ToString());
}
+ return new RServiceResult(true);
}