Iceshrimp.NET/Iceshrimp.Backend/Pages/Queue.cshtml.cs
Laura Hausmann 4a3cf7c2d5
[backend/razor] Indicate scheduled jobs in the queue dashboard
Calling both scheduled and delayed jobs delayed is confusing, even if there's no queue system-internal distinction.
2024-10-15 01:49:16 +02:00

137 lines
No EOL
5 KiB
C#

using System.Collections.Immutable;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Middleware;
using Iceshrimp.Backend.Core.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
namespace Iceshrimp.Backend.Pages;
public class QueueModel(DatabaseContext db, QueueService queueSvc, MetaService meta) : PageModel
{
public int? DelayedCount;
public Job.JobStatus? Filter;
public List<Job> Jobs = [];
public int? NextPage;
public int? PrevPage;
public string? Queue;
public int? QueuedCount;
public int? RunningCount;
public int? TotalCount;
public List<QueueStatus>? QueueStatuses;
public long? Last;
public string InstanceName = "Iceshrimp.NET";
public static readonly ImmutableArray<string> ScheduledQueues = ["background-task", "backfill"];
public async Task<IActionResult> OnGet(
[FromRoute] string? queue, [FromRoute(Name = "pagination")] int? page, [FromRoute] string? status
)
{
if (!Request.Cookies.TryGetValue("admin_session", out var cookie))
return Redirect("/login");
if (!await db.Sessions.AnyAsync(p => p.Token == cookie && p.Active && p.User.IsAdmin))
return Redirect("/login");
Request.HttpContext.HideFooter();
InstanceName = await meta.Get(MetaEntity.InstanceName) ?? InstanceName;
if (queue == null)
{
Jobs = await db.Jobs.OrderByDescending(p => p.LastUpdatedAt).Take(20).ToListAsync();
if (Request.Query.TryGetValue("last", out var last) && long.TryParse(last, out var parsed))
Last = parsed;
//TODO: write an expression generator for the job count calculation
QueueStatuses = await db.Jobs
.GroupBy(job => job.Queue)
.OrderBy(p => p.Key)
.Select(p => p.Key)
.Select(queueName => new QueueStatus
{
Name = queueName,
JobCounts = new Dictionary<Job.JobStatus, int>
{
{
Job.JobStatus.Queued, db.Jobs.Count(job =>
job.Queue == queueName &&
job.Status ==
Job.JobStatus.Queued)
},
{
Job.JobStatus.Delayed, db.Jobs.Count(job =>
job.Queue == queueName &&
job.Status == Job.JobStatus.Delayed)
},
{
Job.JobStatus.Running, db.Jobs.Count(job =>
job.Queue == queueName &&
job.Status == Job.JobStatus.Running)
},
{
Job.JobStatus.Completed, db.Jobs.Count(job =>
job.Queue == queueName &&
job.Status == Job.JobStatus.Completed)
},
{
Job.JobStatus.Failed, db.Jobs.Count(job =>
job.Queue == queueName &&
job.Status ==
Job.JobStatus.Failed)
}
}.AsReadOnly()
})
.ToListAsync();
return Page();
}
if (!queueSvc.QueueNames.Contains(queue))
throw GracefulException.BadRequest($"Unknown queue: {queue}");
Queue = queue;
if (page is null or < 1)
page = 1;
var query = db.Jobs.Where(p => p.Queue == queue);
if (status is { Length: > 0 })
{
if (!Enum.TryParse<Job.JobStatus>(status, true, out var jobStatus))
throw GracefulException.BadRequest($"Unknown status: {status}");
query = query.Where(p => p.Status == jobStatus);
Filter = jobStatus;
}
Jobs = await query.OrderByDescending(p => p.Id)
.Skip((page.Value - 1) * 50)
.Take(50)
.ToListAsync();
if (Filter == null)
{
TotalCount = await db.Jobs.CountAsync(p => p.Queue == queue);
QueuedCount = await db.Jobs.CountAsync(p => p.Queue == queue && p.Status == Job.JobStatus.Queued);
RunningCount = await db.Jobs.CountAsync(p => p.Queue == queue && p.Status == Job.JobStatus.Running);
DelayedCount = await db.Jobs.CountAsync(p => p.Queue == queue && p.Status == Job.JobStatus.Delayed);
}
else
{
TotalCount = await query.CountAsync();
}
if (Jobs.Count >= 50)
NextPage = page + 1;
if (page is > 1)
PrevPage = page - 1;
return Page();
}
public class QueueStatus
{
public required string Name { get; init; }
public required IReadOnlyDictionary<Job.JobStatus, int> JobCounts { get; init; }
}
}