Added inital job entity and services. Added released works API integration.
This commit is contained in:
@@ -18,6 +18,7 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
|
||||
public DbSet<Series> Series { get; set; }
|
||||
public DbSet<VoiceWorkSearch> VoiceWorkSearches { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<Job> Jobs { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
44
JSMR.Infrastructure/Data/Configuration/JobConfiguration.cs
Normal file
44
JSMR.Infrastructure/Data/Configuration/JobConfiguration.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using JSMR.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace JSMR.Infrastructure.Data.Configuration;
|
||||
|
||||
public sealed class JobConfiguration : IEntityTypeConfiguration<Job>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Job> builder)
|
||||
{
|
||||
builder.ToTable("Jobs");
|
||||
|
||||
builder.HasKey(x => x.Id);
|
||||
|
||||
builder.Property(x => x.Code)
|
||||
.HasMaxLength(100)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.RequestedByUserId)
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(x => x.RequestedSource)
|
||||
.HasMaxLength(50)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.WorkerName)
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(x => x.CurrentStep)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(x => x.ResultSummary)
|
||||
.HasMaxLength(2000);
|
||||
|
||||
builder.Property(x => x.Error)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
builder.Property(x => x.ParametersJson)
|
||||
.HasColumnType("LONGTEXT");
|
||||
|
||||
builder.HasIndex(x => new { x.Status, x.CreatedUtc });
|
||||
builder.HasIndex(x => x.Code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using JSMR.Application.Jobs;
|
||||
using JSMR.Domain.Entities;
|
||||
using JSMR.Domain.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace JSMR.Infrastructure.Data.Repositories.Jobs;
|
||||
|
||||
public sealed class JobProgressWriter(AppDbContext dbContext) : IJobProgressWriter
|
||||
{
|
||||
public async Task SetStepAsync(int jobId, string step, CancellationToken canellationToken)
|
||||
{
|
||||
Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
|
||||
|
||||
if (job is null)
|
||||
return;
|
||||
|
||||
job.CurrentStep = step;
|
||||
job.HeartbeatUtc = DateTime.UtcNow;
|
||||
|
||||
await dbContext.SaveChangesAsync(canellationToken);
|
||||
}
|
||||
|
||||
public async Task SetProgressAsync(int jobId, int? current, int? total, CancellationToken canellationToken)
|
||||
{
|
||||
Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
|
||||
|
||||
if (job is null)
|
||||
return;
|
||||
|
||||
job.ProgressCurrent = current;
|
||||
job.ProgressTotal = total;
|
||||
job.HeartbeatUtc = DateTime.UtcNow;
|
||||
|
||||
await dbContext.SaveChangesAsync(canellationToken);
|
||||
}
|
||||
|
||||
public async Task SetHeartbeatAsync(int jobId, CancellationToken canellationToken)
|
||||
{
|
||||
Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
|
||||
|
||||
if (job is null)
|
||||
return;
|
||||
|
||||
job.HeartbeatUtc = DateTime.UtcNow;
|
||||
|
||||
await dbContext.SaveChangesAsync(canellationToken);
|
||||
}
|
||||
|
||||
public async Task CompleteAsync(int jobId, string? summary, CancellationToken canellationToken)
|
||||
{
|
||||
Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
|
||||
|
||||
if (job is null)
|
||||
return;
|
||||
|
||||
job.Status = JobStatus.Succeeded;
|
||||
job.CompletedUtc = DateTime.UtcNow;
|
||||
job.HeartbeatUtc = DateTime.UtcNow;
|
||||
job.ResultSummary = summary;
|
||||
job.CurrentStep = "Completed";
|
||||
|
||||
await dbContext.SaveChangesAsync(canellationToken);
|
||||
}
|
||||
|
||||
public async Task FailAsync(int jobId, string error, CancellationToken canellationToken)
|
||||
{
|
||||
Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
|
||||
|
||||
if (job is null)
|
||||
return;
|
||||
|
||||
job.Status = JobStatus.Failed;
|
||||
job.CompletedUtc = DateTime.UtcNow;
|
||||
job.HeartbeatUtc = DateTime.UtcNow;
|
||||
job.Error = error;
|
||||
job.CurrentStep = "Failed";
|
||||
|
||||
await dbContext.SaveChangesAsync(canellationToken);
|
||||
}
|
||||
}
|
||||
52
JSMR.Infrastructure/Data/Repositories/Jobs/JobRepository.cs
Normal file
52
JSMR.Infrastructure/Data/Repositories/Jobs/JobRepository.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using JSMR.Application.Jobs;
|
||||
using JSMR.Domain.Entities;
|
||||
using JSMR.Domain.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace JSMR.Infrastructure.Data.Repositories.Jobs;
|
||||
|
||||
public sealed class JobRepository(AppDbContext dbContext) : IJobRepository
|
||||
{
|
||||
public async Task<Job> AddAsync(Job job, CancellationToken cancellationToken)
|
||||
{
|
||||
await dbContext.Jobs.AddAsync(job, cancellationToken);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
public Task<Job?> GetByIdAsync(int id, CancellationToken cancellationToken)
|
||||
=> dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
|
||||
public async Task<IReadOnlyList<Job>> GetRecentAsync(int take, CancellationToken cancellationToken)
|
||||
=> await dbContext.Jobs
|
||||
.OrderByDescending(x => x.CreatedUtc)
|
||||
.Take(take)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
public Task<bool> AnyRunningAsync(CancellationToken cancellationToken)
|
||||
=> dbContext.Jobs.AnyAsync(x => x.Status == JobStatus.Running, cancellationToken);
|
||||
|
||||
public async Task<Job?> TryClaimNextQueuedAsync(string workerName, CancellationToken cancellationToken)
|
||||
{
|
||||
Job? next = await dbContext.Jobs
|
||||
.Where(x => x.Status == JobStatus.Queued)
|
||||
.OrderBy(x => x.CreatedUtc)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (next is null)
|
||||
return null;
|
||||
|
||||
next.Status = JobStatus.Running;
|
||||
next.StartedUtc = DateTime.UtcNow;
|
||||
next.HeartbeatUtc = DateTime.UtcNow;
|
||||
next.WorkerName = workerName;
|
||||
next.AttemptCount += 1;
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
public Task SaveChangesAsync(CancellationToken ct)
|
||||
=> dbContext.SaveChangesAsync(ct);
|
||||
}
|
||||
Reference in New Issue
Block a user