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 IBackgroundJobService { Task EnqueueAsync( CreateBackgroundJobCommand command, CancellationToken cancellationToken = default); 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); 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); }