using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using EntityFrameworkCore.Projectables; using Iceshrimp.Backend.Core.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Iceshrimp.Backend.Core.Database.Tables; [Table("jobs")] [Index(nameof(Queue))] [Index(nameof(Status))] [Index(nameof(FinishedAt))] [Index(nameof(DelayedUntil))] [Index(nameof(Mutex), IsUnique = true)] public class Job { public enum JobStatus { Queued, Delayed, Running, Completed, Failed } [Key] [Column("id")] public Guid Id { get; set; } [Column("queue")] public string Queue { get; set; } = null!; [Column("status")] public JobStatus Status { get; set; } [Column("queued_at")] public DateTime QueuedAt { get; set; } [Column("started_at")] public DateTime? StartedAt { get; set; } [Column("finished_at")] public DateTime? FinishedAt { get; set; } [Column("delayed_until")] public DateTime? DelayedUntil { get; set; } [Column("retry_count")] public int RetryCount { get; set; } [Column("exception_message")] public string? ExceptionMessage { get; set; } [Column("exception_source")] public string? ExceptionSource { get; set; } [Column("stack_trace")] public string? StackTrace { get; set; } [Column("exception")] public string? Exception { get; set; } [Column("data")] public string Data { get; set; } = null!; [Column("mutex")] public string? Mutex { get; set; } [NotMapped] public long Duration => ((FinishedAt ?? DateTime.UtcNow) - (StartedAt ?? QueuedAt)).GetTotalMilliseconds(); [NotMapped] public long QueueDuration => ((StartedAt ?? DateTime.UtcNow) - QueuedAt).GetTotalMilliseconds(); [NotMapped] [Projectable] public DateTime LastUpdatedAt => FinishedAt ?? StartedAt ?? QueuedAt; private class EntityTypeConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder entity) { entity.Property(e => e.Id).ValueGeneratedNever(); entity.Property(e => e.Status).HasDefaultValue(JobStatus.Queued); entity.Property(e => e.QueuedAt).HasDefaultValueSql("now()"); } } }