using System.Text.Json; using Tiku.Domain.Operations; namespace Tiku.Application.Jobs; public sealed class BackgroundJobException(string code, string message) : Exception(message) { public string Code { get; } = code; } public sealed record CreateBackgroundJobCommand( Guid TenantId, string JobType, JsonElement Payload, DateTimeOffset? RunAfter = null, int MaxRetries = 3, string? IdempotencyKey = null, bool IsSystemJob = false); public sealed record BackgroundJobItem( Guid Id, Guid TenantId, string JobType, string? IdempotencyKey, BackgroundJobStatus Status, int RetryCount, int MaxRetries, DateTimeOffset? RunAfter, DateTimeOffset? StartedAt, DateTimeOffset? CompletedAt, DateTimeOffset? CancellationRequestedAt, Guid? CancellationRequestedBy, string? CancellationReason, string? LastError, Guid? OutputAssetId, JsonElement Result); public interface IBackgroundJobQueue { Task EnqueueAsync( CreateBackgroundJobCommand command, CancellationToken cancellationToken = default); } public interface IBackgroundJobProcessor { Task ProcessPendingAsync( string workerId, int batchSize, bool includeImmediateJobs = true, CancellationToken cancellationToken = default); Task ProcessRequestedAsync( Guid jobId, Guid tenantId, string jobType, string workerId, CancellationToken cancellationToken = default); } public interface IBackgroundJobOperations { Task> ListAsync( Guid tenantId, string? jobType = null, int limit = 50, CancellationToken cancellationToken = default); Task GetAsync( Guid jobId, Guid? tenantId, CancellationToken cancellationToken = default); Task> ListPlatformAsync( Guid? tenantId = null, string? jobType = null, BackgroundJobStatus? status = null, int limit = 100, CancellationToken cancellationToken = default); Task RequestCancellationAsync( Guid jobId, Guid? tenantId, Guid actorUserId, string reason, CancellationToken cancellationToken = default); Task RetryAsync( Guid jobId, Guid? tenantId, Guid actorUserId, CancellationToken cancellationToken = default); } public interface IBackgroundJobService : IBackgroundJobQueue, IBackgroundJobProcessor, IBackgroundJobOperations; public sealed record BackgroundJobExecutionContext( Guid JobId, Guid TenantId, string JobType, JsonElement Payload); public interface IBackgroundJobHandler { string JobType { get; } Task HandleAsync( BackgroundJobExecutionContext context, CancellationToken cancellationToken = default); }