.NET API
IJobStore
Tracon.Abstractions.dllThe store for queued jobs and their items.
public interface IJobStoreRemarks
Section titled “Remarks”The PostgreSql implementation leases with FOR UPDATE SKIP LOCKED:
even if multiple workers connect to the same database, a job is picked up
by only one worker. The in-memory implementation provides the same
contract with a lock and a timestamp.
Important: IJobStore.ReportItemAsync and state transitions must be idempotent — the same item may be reported twice if the lease expires and the job is re-leased.
Methods
Section titled “Methods”CancelAsync(string, Guid, CancellationToken)
Section titled “ CancelAsync(string, Guid, CancellationToken)”Tries to cancel a job. Only a job in the JobStatus.Pending, JobStatus.Leased, or JobStatus.Running state can be cancelled.
ValueTask<bool> CancelAsync(string tenantId, Guid jobId, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”tenantId string
The tenant identifier.
jobId Guid
The job identifier.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”true if the cancellation happened.
CompleteAsync(JobCompletion, CancellationToken)
Section titled “ CompleteAsync(JobCompletion, CancellationToken)”Finalizes a job.
ValueTask CompleteAsync(JobCompletion completion, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”completion JobCompletion
The finalization information.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The completion task.
Remarks
Section titled “Remarks”Only an open job (JobStatus.Pending, JobStatus.Leased or JobStatus.Running) is finalized; the call leaves a job that already reached a terminal status unchanged. A cancelled job stays JobStatus.Cancelled even when its handler throws afterwards.
EnqueueAsync(JobRecord, IReadOnlyList<string>, CancellationToken)
Section titled “ EnqueueAsync(JobRecord, IReadOnlyList<string>, CancellationToken)”Enqueues a new job and creates its items.
ValueTask<JobRecord> EnqueueAsync(JobRecord job, IReadOnlyList<string> items, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”job JobRecord
The job record. JobRecord.Status is ignored; the store always starts it with JobStatus.Pending.
items IReadOnlyList<string>
The job’s input list. Sequence numbers are assigned by list order.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The created job record.
Remarks
Section titled “Remarks”Resolve the stored lane with JobLanes.Resolve, passing the
configured TraconSchedulingOptions.LaneByHandlerKey map. That map is
applied here and nowhere else, so a store that skips the call silently
ignores it.
A job id that is already stored is refused: the call throws, and the stored job and its items do not change. A queued run’s job carries the run’s id, and two callers can write the same job at the same time (a repeated answer that writes the job a crash left missing); the refusal is what keeps the work from running twice. A store that replaced the job would reset a leased job to JobStatus.Pending.
GetAsync(string, Guid, CancellationToken)
Section titled “ GetAsync(string, Guid, CancellationToken)”Fetches a single job record.
ValueTask<JobRecord?> GetAsync(string tenantId, Guid jobId, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”tenantId string
The tenant identifier.
jobId Guid
The job identifier.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The record; null if it does not exist or belongs to another tenant.
GetQueueDepthAsync(CancellationToken)
Section titled “ GetQueueDepthAsync(CancellationToken)”Counts the jobs still outstanding, grouped by lane and status.
ValueTask<IReadOnlyList<JobQueueDepth>> GetQueueDepthAsync(CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<JobQueueDepth>>
One record per lane/status pair that has at least one open job. A pair with no open jobs is omitted rather than reported as zero.
Remarks
Section titled “Remarks”Only the open statuses are counted — JobStatus.Pending,
JobStatus.Leased, and JobStatus.Running. The
terminal ones are already counted by the
tracon.job.executions counter as each job finishes; counting
them here would make the query’s cost grow with the queue’s whole
history instead of with the work that is actually outstanding.
This is an aggregate query, deliberately placed on this interface rather than split into a separate one — the same layout IRunStore.GetStatisticsAsync already uses. It takes no tenant argument: queue depth is an operator signal about the worker pool, which leases across every tenant (IJobStore.LeaseAsync), so there is no tenant boundary to apply here.
The SQL implementations answer this from the jobs_claim_idx
index, whose partial condition covers exactly these three statuses.
LeaseAsync(JobLeaseRequest, CancellationToken)
Section titled “ LeaseAsync(JobLeaseRequest, CancellationToken)”Leases the oldest job ready to run. Returns null if no such job exists.
ValueTask<JobRecord?> LeaseAsync(JobLeaseRequest request, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”request JobLeaseRequest
The lease request: the worker, the lease duration, the lanes (JobLeaseRequest.Lanes, null or empty applies no filter) and an optional per-tenant ceiling (JobLeaseRequest.TenantCap).
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The leased job; null if none exists.
Remarks
Section titled “Remarks”With JobLeaseRequest.TenantCap set, a ready job whose handler key is in the cap’s keys is skipped while its tenant already holds the cap’s number of live leases on those keys; the oldest job that is still eligible is leased instead. A job with an expired lease is not counted, and it can be leased again. With no cap the oldest ready job is leased, whichever tenant owns it.
The count is read, not locked: workers that lease at the same moment can take the tenant past the ceiling by up to their own number (see JobTenantCap).
ListItemsAsync(Guid, CancellationToken)
Section titled “ ListItemsAsync(Guid, CancellationToken)”Lists a job’s items, by sequence number.
ValueTask<IReadOnlyList<JobItemRecord>> ListItemsAsync(Guid jobId, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”jobId Guid
The job identifier.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<JobItemRecord>>
The items.
MarkRunningAsync(Guid, string, CancellationToken)
Section titled “ MarkRunningAsync(Guid, string, CancellationToken)”Transitions a leased (JobStatus.Leased) job to JobStatus.Running. The worker calls this right after obtaining the lease, before starting execution.
ValueTask<bool> MarkRunningAsync(Guid jobId, string owner, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”jobId Guid
The job identifier.
owner string
The identifier of the worker holding the lease. The operation is ignored if it does not match.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”true if the transition happened.
QueryAsync(JobQuery, CancellationToken)
Section titled “ QueryAsync(JobQuery, CancellationToken)”Lists jobs by filter. The newest record is returned first.
ValueTask<IReadOnlyList<JobRecord>> QueryAsync(JobQuery query, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”query JobQuery
The filter.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<JobRecord>>
The records.
ReleaseForRetryAsync(Guid, string, TimeSpan?, CancellationToken)
Section titled “ ReleaseForRetryAsync(Guid, string, TimeSpan?, CancellationToken)”Returns a job to the JobStatus.Pending state; releases its lease. JobRecord.Attempt does not change here since it is already incremented at lease time.
ValueTask ReleaseForRetryAsync(Guid jobId, string errorMessage, TimeSpan? retryAfter = null, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”jobId Guid
The job identifier.
errorMessage string
The most recent attempt’s error.
retryAfter TimeSpan?
The time to wait before the next attempt. If null or zero, the job may be re-leased immediately (the old behavior).
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The completion task.
Remarks
Section titled “Remarks”retryAfter pushes the JobRecord.ScheduledFor
field forward; since the lease query already applies
scheduled_for <= now, backoff needs no additional mechanism.
Webhook delivery builds its 1 min / 5 min / 30 min / 2 hr / 6 hr ladder with this parameter. No second queue or second lease mechanism is written.
Like IJobStore.CompleteAsync, the call leaves a job in a terminal status unchanged: a cancelled job never returns to JobStatus.Pending.
RenewLeaseAsync(Guid, string, TimeSpan, CancellationToken)
Section titled “ RenewLeaseAsync(Guid, string, TimeSpan, CancellationToken)”Extends an in-progress job’s lease. Does not change the job’s status.
ValueTask RenewLeaseAsync(Guid jobId, string owner, TimeSpan leaseDuration, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”jobId Guid
The job identifier.
owner string
The identifier of the worker holding the lease. The operation is ignored if it does not match.
leaseDuration TimeSpan
The new lease duration.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The completion task.
ReportItemAsync(JobItemResult, CancellationToken)
Section titled “ ReportItemAsync(JobItemResult, CancellationToken)”Reports an item’s processing result and updates the job’s JobRecord.DoneItems/JobRecord.FailedItems counters.
ValueTask ReportItemAsync(JobItemResult item, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”item JobItemResult
The item result.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”The completion task.
Remarks
Section titled “Remarks”Only an item that is still JobItemStatus.Pending is changed. A report for an item that already finished changes neither the item nor the counters, so an item re-reported after a lease takeover is counted once.
A report whose status is JobItemStatus.Pending is a marker: it records JobItemResult.RunId on the item, leaves the item pending, and counts nothing. A later report that finishes the item is counted as usual.