fix: batch-processing subjob status reporting + redesign jobs page UI (#76) #77
Dismiss Review
Are you sure you want to dismiss this review?
Labels
Clear labels
AI Gen
area:auth
area:backend
area:ci
area:db
area:frontend
area:shared
good first issue
Need Triage
page:admin-users
page:album-detail
page:albums
page:cosplayer-detail
page:cosplayers
page:home
page:jobs
page:login
page:photos
page:register
page:settings
page:stats
page:user
performance
priority:critical
priority:high
priority:low
priority:medium
type:docs
type:refactor
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
Autogenerated By AI
Authentication, JWT, refresh tokens
Lactose API (controllers, repos, services, models)
Docker, CI/CD, Gitea Actions
EF Core, migrations, pgvector
MilkStream WASM client (Blazor UI, SCSS, components)
Butter shared library (DTOs, enums, MIME types)
Good for new contributors
Needs to be categorized by a Human
Admin user management (/Users)
Album detail page (/albums/{id})
Albums list (/albums)
Cosplayer detail page (/cosplayer/{id})
Cosplayers list (/cosplayers)
Home page (/)
Background jobs page (/Jobs)
Login page (/login)
Photos page (/photos)
Register page (/Register)
Settings page (/Settings)
Statistics page (/Stats)
User profile page (/User/{id})
Performance or scalability concern
Blocker / must fix immediately
Must fix / urgent
Nice to have
Should fix
Documentation
Code cleanup or refactoring
Something is not working
This issue or pull request already exists
New feature
Need some help
Something is wrong
More information is needed
This won't be fixed
Milestone
No items
No Milestone
v1.0 - Initial Release
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: MilkyShots/MilkyShots#77
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #76
Part 1: Subjob status reporting fix
Subjob status (all 4 slave jobs)
After the asset processing loop, the slave now checks
failedAssets:JobStatus.Fail(...)JobStatus.CompleteWithErrors(...)JobStatus.Complete(...)Previously all three cases called
JobStatus.Complete(...)unconditionally.Race condition fix (all 4 master Done handlers)
Replaced
failedAssets += sub.failedAssetswithInterlocked.Add(ref failedAssets, sub.failedAssets).Files:
Lactose/Jobs/PreviewJob.csLactose/Jobs/ThumbnailJob.csLactose/Jobs/MetadataJob.csLactose/Jobs/PHashJob.csPart 2: Jobs page UI redesign
Unified tabbed view
Search, filter, sort
bi-searchicon)EJobType+ All)EJobStatus+ All)Status summary strip
Job type badges
EJobType(inspired byAccessLevelBadgeon Users page)Mobile responsive
d-md-none): Compact card with icon, name, type badge, status dot, progress bar, elapsedTree spacing
ms-*indentationFiles:
MilkStream.Client/Components/Pages/Jobs.razor(rewritten)MilkStream.Client/Components/Pages/Jobs.razor.css(new)MilkStream.Client/Components/JobRow.razor(rewritten)MilkStream.Client/Components/JobTree.razor(updated)Testing needed
changes look fine, however there is a strange counting bug. A job with a single subjob that fails 12 assets, will show on the master job as 13 out of 12 failed.
WIP: fix: batch-processing subjobs report correct status on asset failures (#76)to fix: batch-processing subjob status reporting + redesign jobs page UI (#76)Addressed the double-counting bug — removed the
Interlocked.Increment(ref failedAssets)from the master Done handler in all 4 job types. The subjob'sfailedAssetsis now the sole source of truth, so 12 failed assets in a batch = 12 counted, no more +1 for the subjob status.Can we NOT push the damn compose file everytime?
@@ -56,7 +56,7 @@environment:# LactoseBaseUrl must be the address the *browser* can reach Lactose at.# Override this with your server's hostname/IP if not running on localhost.- LactoseBaseUrl=http://192.168.50.100:5162/This again?
Still a problem btw. This needs a revert.
- JobTree polls children for all Level 0 active roots (not just expanded), so segment progress bars update on collapsed rows too - Add PollChildren helper to deduplicate fetch logic - OnExpanded only stops refresh when no active roots remain - Store UtcNow as fallback when server x-delta-timestamp is missing - Fix segment colors: share ToCssClass between single and stacked bars, use text-bg-* classes for proper Bootstrap 5.3 progress-bar override - Replace status words with Bootstrap icons in child summary (e.g. "15 Running" → "15 🔃") for compact displaySee the relevant comments on open discussions
docker-compose.yml reverted to develop's LactoseBaseUrl=http://192.168.50.100:5162/
@@ -52,2 +54,3 @@if (accessLevel != EAccessLevel.Admin) { return Unauthorized(); }return Ok(jobManager.GetChildren(parentId));var (children, responseTime) = jobManager.GetChildren(parentId, since);Response.Headers["x-delta-timestamp"] = responseTime.ToString("O");headers should only be used for metadata around a request working, not as actual parameters for a query, if it is needed to handle a starting time, it should be passed as part of a DTO.
the specific "x-delta-timestamp" is used for profiling or time synced operations
this is more of a request to select a specific group of jobs, also may be used in conjunction with a "latest", for visualizing all the jobs inside a time window (can be used for debug feature)
@Ai_Agent the header isn't even in use and should be removed.
@@ -51,0 +51,4 @@/// <param name="parentId">The parent job ID.</param>/// <param name="since">If set, only children changed after this timestamp are returned. Null returns all children.</param>/// <returns>A tuple of children and the response timestamp to use for the next delta poll.</returns>public (List<JobStatusDto> Children, DateTime Since) GetChildren(Guid parentId, DateTime? since) {Because DateTime happens at the return, it can be directly generated from the caller of the method instead of being made every time, even if you may not care about the time.
Ttuple as return type make the code stinky because isn't cleanly hineritable. JobManager is actually a Service and it should follow the same policy of APIs so specific data structure should always be used to couple informations.
@Ai_Agent should be moved to the controller and keep the signature cleaner
@@ -54,3 +59,3 @@foreach (var job in activeJobs.Values) {if (job.ParentJobId == parentId) {results.Add(job.ToJobStatusDto());if (since is null || job.JobStatus.LastChange > since.Value) {The search may be long with a big list of jobs running; it could be favorable to use parallel access to the data structure.
@Ai_Agent Should probably be converted in a LINQ query.
Addressed all review comments from Fastwind (review #42):
ChildrenResponseDTO that includesChildren+SinceJobManager.GetChildrennow returnsList<JobStatusDto>directly,DateTime.UtcNowmoved to controlleractiveJobs.Values.Where().Select()instead of manual loopConcurrentDictionary.Valuesis thread-safe; the LINQ query enumerates at the call site(commit
89c91b2)