Coming soon. Depotex is in active development, so features and these docs may still change.

Scheduled Jobs

View, configure and run the background jobs Depotex runs for you

1. Overview

The application includes a built-in job scheduler that automatically runs recurring maintenance tasks and background operations. As an administrator, you can view, configure, and manually trigger these jobs through the Scheduler management UI.

2. Accessing the Scheduler

Go to Settings → Advanced → Scheduled Jobs to see every registered job and its current status.

Required permission: scheduler:read to view jobs, scheduler:write to modify them.

3. Understanding the Job List

The scheduler dashboard shows all registered jobs with the following information:

ColumnDescription
NameUnique identifier for the job
StatusEnabled or Disabled — whether the job is actively running on schedule
ScheduleCron expression showing when the job runs (e.g., "Every hour", "Daily at 3:30 AM")
Last RunWhen the job last executed and whether it succeeded or failed
Next RunWhen the job is scheduled to run next
HealthGreen (healthy), Yellow (recent failure), Red (multiple consecutive failures)
Settings → Advanced → Scheduled jobs
Settings → Advanced → Scheduled jobs

4. Job Statuses

Each job run is recorded with one of these statuses:

StatusMeaning
✅ SuccessThe job completed without errors
❌ FailureThe job encountered an error (see run history for details)
⏱️ TimeoutThe job exceeded its maximum allowed duration and was cancelled
⏭️ SkippedThe job was skipped (e.g., blocked by a plugin hook or already running)

5. Configuring Jobs

Changing the Schedule

If a job has the "Schedule Editable" flag (shown as a pencil icon next to the schedule), you can change when it runs:

  1. Click the pencil icon on the job's row
  2. Enter a new cron expression (in UTC) or interval
  3. Check Next run, shown in your own time zone under the field
  4. Click Save Changes

Cron schedules are in UTC on every server, and the Schedule column marks them UTC. Last and next run times are shown in your own time zone, so 0 8 * * * reads 13:30 for someone in India.

Editing a job's schedule, with the next run in the viewer's time
Editing a job's schedule, with the next run in the viewer's time

The new schedule takes effect immediately — no restart required.

Cron expression format: minute hour day-of-month month day-of-week

ExpressionMeaning
0 * * * *Every hour at minute 0
30 3 * * *Daily at 3:30 AM
0 0 * * 0Weekly on Sunday at midnight
0 */6 * * *Every 6 hours
0 9 * * 1-5Weekdays at 9:00 AM

Changing Job Parameters (Metadata)

Some jobs have configurable parameters (e.g., retention days, batch size). If a job has the "Metadata Editable" flag:

  1. Click the job name to open its detail view
  2. Click Edit Parameters
  3. Modify the values (each parameter has a description and valid range)
  4. Click Save

Changes take effect on the next scheduled run.

Enabling / Disabling Jobs

If a job has the "Toggleable" flag:

  1. Click the toggle switch next to the job name
  2. Confirm the action

Disabled jobs will not run on their schedule but remain registered. Re-enabling them resumes normal scheduling.

Some system-critical jobs (like session cleanup) cannot be disabled — they are marked as non-toggleable.

6. Manual Execution

If a job has the "Manual Run" flag (shown as a play button ▶️):

  1. Click the Run Now button next to the job
  2. The job will execute immediately using its current configuration

  • Manual runs use the same parameters (metadata) as scheduled runs
  • If the job is already running (on another node), the manual run will be rejected with a "conflict" message
  • Manual runs are recorded in run history just like scheduled runs

7. Viewing Run History

Each job maintains a detailed execution history:

  1. Click the job name to open its detail view
  2. Select the Run History tab

Each run record shows:

  • Started At — When the execution began
  • Duration — How long it took
  • Status — Success, Failure, Timeout, or Skipped
  • Node — Which server node executed the job (in multi-node deployments)
  • Attempt — Retry attempt number (if retries are configured)
  • Error — Error message (for failed runs)
  • Parameters — Snapshot of the metadata used for that specific run

Run history is automatically cleaned up after the configured retention period (default: 30 days, minimum 50 runs per job are always kept).

Jobs that run every few seconds or every minute (for example mail-dispatch, event-dispatch and directory-sync) keep only failed and timed-out runs in their history, and the history panel says so. Their successful runs still update Last run in the list.

A job can ship switched off (the scheduled backup does): it stays listed and runs once you switch it on. Switching a job on or off, or changing its schedule, reaches every server of a cluster within one tick of the job.

8. Built-in Jobs

The application ships with these pre-configured jobs:

Session Cleanup (auth-session-cleanup)

SettingValue
ScheduleEvery hour (0 * * * *)
PurposeRemoves sign-in sessions that were revoked, or could no longer be renewed, more than retention_days ago. A “Remember me” session is kept while it can still be renewed (30 days)
Parameterretention_days — how many days after a session ends to keep it (default: 7)
ToggleableNo (always runs)
Schedule EditableYes
Manual RunYes

Scheduled Backup (backup-scheduled)

SettingValue
ScheduleDaily at 2:00 AM (0 2 * * *, or BACKUP_SCHEDULE)
PurposeTakes a backup of the database and platform files and checks it. See Backups
DefaultOff: switch it on to start taking backups
Missed runsRuns once when a server starts after a missed time
ToggleableYes
Schedule EditableYes
Manual RunYes

Backup Cleanup (backup-cleanup)

SettingValue
ScheduleDaily at 3:00 AM (0 3 * * *, or BACKUP_CLEANUP_SCHEDULE)
PurposeDeletes backups older than retention_days, never one kept permanently nor the newest verified backup; also marks backups whose server stopped reporting as failed
Parameterretention_days — days to keep a backup (default: 7, or BACKUP_RETENTION_DAYS)
ToggleableYes
Schedule EditableYes
Manual RunYes

API Token Cleanup (apitoken-cleanup)

SettingValue
ScheduleDaily at 3:30 AM (30 3 * * *)
PurposeRemoves API tokens that expired or were revoked more than retention_days ago, so they stay listed (as Expired or Revoked) for a while first
Parameterretention_days — how many days after a token expires or is revoked to keep it (default: 90, or API_TOKEN_RETENTION_DAYS)
ToggleableNo (always runs)
Schedule EditableYes
Manual RunYes

Download Usage (download-usage)

SettingValue
ScheduleEvery 5 minutes (5m)
PurposeCopies the day's download totals per person, token, AI app, organization and repository to the database for the download report, restores Redis's totals after it restarted or failed over, and deletes totals older than retention_days. Addresses are never stored
Parameterretention_days — days of totals to keep (default: 90, or DOWNLOAD_USAGE_RETENTION_DAYS)
Run historyOnly failed runs are recorded
ToggleableNo (always runs)
Schedule EditableYes
Manual RunYes

Token Usage (token-usage-flush)

SettingValue
ScheduleEvery minute, on every server
PurposeEach server counts API token requests and saves each token's request count and last-used time every few seconds (API_TOKEN_USAGE_FLUSH_INTERVAL, 5s); this job saves what a server that went quiet still holds
Run historyOnly failed runs are recorded
ToggleableNo
Schedule EditableNo
Manual RunNo

Run History Cleanup (scheduler-run-history-cleanup)

SettingValue
ScheduleDaily at 3:00 AM (0 3 * * *)
PurposeCleans up old job execution records to prevent unbounded database growth
Parametersretention_days (default: 30), min_runs_per_job (default: 50)
ToggleableYes
Schedule EditableYes
Manual RunYes

Event Delivery (event-dispatch)

SettingValue
ScheduleEvery few seconds (EVENT_DISPATCH_INTERVAL, default 5s)
PurposeDelivers events to alert rules, plugins and automation, retrying failures
Run historyOnly failed runs are recorded, so the history stays readable
ToggleableNo (always runs)
Schedule EditableNo
Manual RunNo

Search Change Cleanup (index-events-prune)

SettingValue
ScheduleHourly at :25 UTC (25 * * * *, INDEX_EVENTS_PRUNE_SCHEDULE)
PurposeDeletes search index changes older than a day, after every server has applied them; a server that was down longer than that rebuilds its search index when it starts
ToggleableNo
Schedule EditableYes
Manual RunYes

Event Cleanup (event-outbox-cleanup)

SettingValue
ScheduleDaily at 4:15 AM (15 4 * * *, EVENT_OUTBOX_CLEANUP_SCHEDULE)
PurposeRemoves delivered events after EVENT_OUTBOX_RETENTION_DAYS (7) and failed ones after EVENT_DEAD_RETENTION_DAYS (30)
ToggleableNo (always runs)
Schedule EditableYes
Manual RunYes

Policy Compliance Check (policy-compliance-scan)

SettingValue
ScheduleDaily at 03:30 UTC (POLICY_SCAN_SCHEDULE)
PurposeChecks existing API tokens and repositories against each block and warn policy and lists what they would affect (read-only)
ToggleableYes
Schedule EditableYes
Manual RunYes

Automation Run Cleanup (automation-run-cleanup)

SettingValue
ScheduleDaily at 04:50 UTC (AUTOMATION_RUN_CLEANUP_SCHEDULE)
PurposeRemoves automation runs older than AUTOMATION_RUN_RETENTION_DAYS (30)
ToggleableNo
Schedule EditableYes
Manual RunYes

Directory Sync (directory-sync)

SettingValue
ScheduleEvery minute (DIRECTORY_SYNC_CHECK_INTERVAL)
PurposeSyncs each LDAP and Active Directory directory that is due, at that directory's own interval (see Users & Directories)
ToggleableYes (turning it off stops all directory syncs)
Schedule EditableNo
Manual RunNo (use Sync now on the directory)

Directory Sync History Cleanup (directory-sync-run-cleanup)

SettingValue
ScheduleDaily at 04:40 UTC (DIRECTORY_SYNC_RUN_CLEANUP_SCHEDULE)
PurposeRemoves directory sync runs finished more than 90 days ago
ToggleableNo
Schedule EditableYes
Manual RunYes

Email Delivery (mail-dispatch)

SettingValue
ScheduleEvery 10 seconds (MAIL_DISPATCH_INTERVAL)
PurposeSends queued email and retries failed deliveries (see Email)
ToggleableNo
Schedule EditableNo
Manual RunNo

Email History Cleanup (mail-cleanup)

SettingValue
ScheduleDaily at 04:30 UTC (MAIL_CLEANUP_SCHEDULE)
PurposeRemoves records of sent and failed email older than 30 days
ToggleableNo
Schedule EditableYes
Manual RunYes

Deleted Repositories (repository-purge)

SettingValue
ScheduleDaily at 04:30, once per cluster
PurposeRemoves deleted repositories for good once they have been kept retention_days (7), and at once those a super admin deleted permanently (which starts a run straight away). What a repository held goes in batches of batch_size versions (1000), then the repository itself. Until then a deleted repository can be restored (Settings → Deleted repositories). A run stops after 2 hours and the next one carries on
ToggleableNo
Schedule EditableYes
Metadata EditableYes (retention_days, batch_size)
Manual RunYes

Repository Metadata Rebuilds (repository-repair)

SettingValue
ScheduleEvery minute, once per cluster
PurposeRuns the metadata rebuilds repository admins asked for (Check or Repair in a repository's Metadata card), one at a time
Run historyOnly failed runs are recorded
ToggleableNo
Schedule EditableYes
Manual RunYes

Old Metadata Rebuilds (repository-repair-prune)

SettingValue
ScheduleDaily at 04:40, once per cluster
PurposeForgets rebuilds finished more than 30 days ago, keeping each repository's latest
ToggleableNo
Schedule EditableYes
Manual RunYes

Background Promotions (promotion-run)

SettingValue
ScheduleEvery minute, once per cluster
PurposeRuns the promotions asked to run in the background, one at a time, with the access the person who asked had then (Pro)
Run historyOnly failed runs are recorded
ToggleableNo
Schedule EditableYes
Manual RunYes

Old Promotions (promotion-prune)

SettingValue
ScheduleDaily at 04:50, once per cluster
PurposeForgets background promotions finished more than 30 days ago
ToggleableNo
Schedule EditableYes
Manual RunYes

Unused Artifact Content (artifact-blob-gc)

SettingValue
ScheduleHourly at :20
PurposeEach distinct file content is stored once, however many repositories hold it. Deletes content no file uses any more (after deletes, overwrites and emptied trash) once unused for ARTIFACT_BLOB_GC_GRACE (1 hour)
ToggleableNo
Schedule EditableYes
Manual RunYes

Download Counts (artifact-download-flush)

SettingValue
ScheduleEvery minute, on every server
PurposeEach server counts downloads and saves files' and versions' download counts and last-downloaded times every few seconds (ARTIFACT_DOWNLOAD_FLUSH_INTERVAL, 5s); this job saves what a server that went quiet still holds
Run historyOnly failed runs are recorded
ToggleableNo
Schedule EditableNo
Manual RunNo

Abandoned Uploads (artifact-upload-temp-cleanup)

SettingValue
ScheduleHourly at :40
PurposeRemoves temporary files of uploads interrupted by a server stopping, after ARTIFACT_UPLOAD_TEMP_TTL (24 hours)
ToggleableNo
Schedule EditableYes
Manual RunYes

Unused Docker Layers (docker-gc)

SettingValue
ScheduleDaily at 03:15
PurposeRemoves manifests and layers of hosted Docker repositories that no tag uses any more, once older than DOCKER_GC_GRACE (24 hours)
ToggleableYes
Schedule EditableYes
Manual RunYes

Unfinished Docker Uploads (docker-upload-cleanup)

SettingValue
ScheduleHourly at :50
PurposeForgets layer uploads not finished within DOCKER_UPLOAD_TTL (24 hours)
ToggleableNo
Schedule EditableYes
Manual RunYes

RubyGems Index Warm-up (rubygems-index-warm)

SettingValue
ScheduleEvery minute (1m), once per cluster
PurposeMakes the first copy of the upstream's list of gems (versions) for each new RubyGems proxy, then the list of each new or changed RubyGems group, so the first bundle install through them isn't asked to try again (503). Proxies and groups whose list exists are left alone; a proxy whose upstream can't be asked now is skipped, and its first client makes the copy
Run historyOnly failed runs are recorded
ToggleableYes (off: the first request to each new proxy or group makes its list)
Schedule EditableYes
Manual RunYes

RubyGems Index Compaction (rubygems-index-compact)

SettingValue
ScheduleDaily at 03:40 (40 3 * * *), once per cluster
PurposeTidies the copies RubyGems proxies keep of their upstream's list of gems, and the lists RubyGems groups keep: gives a group's list a fresh start once what was added to it passes appended_ratio percent of it, or its last fresh start is older than max_age_days (each Bundler client then downloads it once in full), joins the small pieces each update adds into larger ones, forgets a group's list for a set of members nobody has read for 7 days, and deletes copies replaced or no longer used (their repository or upstream deleted or changed) once they are older than grace_minutes. Apart from those full downloads, clients notice nothing
Parameterssmall_chunks — how many small pieces a copy may have before they are joined (default: 256); grace_minutes — how long a replaced copy is kept for downloads still reading it (default: 60; keep it at an hour or more); appended_ratio — how much a group's list may grow, in percent of its last fresh start, before it gets a new one (default: 25); max_age_days — how old a group's fresh start may get, once anything was added to it, before it gets a new one (default: 31)
ToggleableYes
Schedule EditableYes
Metadata EditableYes (small_chunks, grace_minutes, appended_ratio, max_age_days)
Manual RunYes

Unfinished Conan Uploads (conan-upload-cleanup)

SettingValue
ScheduleHourly at :55
PurposeForgets the files of Conan revision uploads whose manifest didn't arrive within CONAN_UPLOAD_TTL (24 hours), deletes files an interrupted upload stored for no revision, once over an hour old, and deletes the search answers Conan proxies keep once nobody has asked for them for 24 hours, keeping at most the 1,000 asked most recently in each proxy (a search asked again fetches its answer again)
ToggleableNo
Schedule EditableYes
Manual RunYes

Artifact Inspection (browse-inspect)

SettingValue
ScheduleEvery 10 seconds
PurposeReads newly published or fetched versions for the browser: dependencies, SBOMs, signatures and attestations; quarantines versions carrying unsafe content (see Browse)
ToggleableNo
Schedule EditableNo
Manual RunNo

Ended Quarantines (quarantine-expiry)

SettingValue
ScheduleEvery 15 minutes
PurposeRecords quarantines set by age rules whose time is up as released (they stop applying at that moment anyway) and raises artifact.release
ToggleableNo
Schedule EditableYes
Manual RunYes

9. Multi-Node Behavior

In clustered deployments (multiple application nodes), the scheduler ensures:

  • Singleton jobs run on exactly one node per scheduled interval — no duplicate execution
  • Any node can pick up a job — the first to acquire the distributed lock wins
  • If a node crashes mid-job, the lock automatically expires and another node picks it up on the next scheduled run
  • The Node column in run history shows which server executed each run

You do not need to configure anything for this. The lock is kept in PostgreSQL, so jobs keep running once per cluster while Redis is unavailable.

10. Health Monitoring

The scheduler tracks job health based on consecutive failures:

Health StateMeaning
🟢 HealthyJob is running successfully
🟡 WarningJob failed once or twice recently
🔴 UnhealthyJob has failed 3+ times consecutively

When a job becomes unhealthy:

  • An alert event is fired (can be consumed by notification plugins)
  • The job continues to run on schedule — it is NOT automatically disabled
  • When the job succeeds again, it returns to healthy status and a recovery event is fired

11. Permissions

PermissionScopeWhat it allows
scheduler:readViewSee all jobs, their status, and run history
scheduler:writeManageChange schedules, toggle jobs, edit parameters, trigger manual runs

12. Troubleshooting

"Job is currently executing, conflict"

This means the job is already running on another node. Wait for it to complete, or check the run history to see if it's stuck (exceeding its max duration).

Job shows as "Timeout"

The job exceeded its maximum allowed execution time and was cancelled. This could mean:

  • The operation is taking longer than expected (e.g., large dataset to clean up)
  • There's a performance issue with the underlying operation
  • Contact your system administrator to investigate or increase the timeout

Job keeps failing (Unhealthy)

Check the run history for error messages. Common causes:

  • Database connectivity issues
  • Insufficient permissions for the cleanup operation
  • Resource constraints (memory, disk space)

Schedule changes not taking effect

  • Verify you have scheduler:write permission
  • Check that the job has "Schedule Editable" enabled
  • Ensure the cron expression is valid (the UI validates this before saving)

Job not running at expected time

  • Check if the job is disabled (toggle switch)
  • In multi-node deployments, the job runs on one node — check all nodes' logs
  • The schedule uses UTC time — verify your timezone expectations

13. Environment Variables (Server Configuration)

These are configured by the system administrator at deployment time:

VariableDefaultDescription
SCHEDULER_RUN_HISTORY_RETENTION_DAYS30Default days to keep run history
API_TOKEN_USAGE_FLUSH_INTERVAL5sHow long a server keeps API token request counts and last-used times before saving them (up to 1m)
ARTIFACT_DOWNLOAD_FLUSH_INTERVAL5sHow long a server keeps download counts and last-downloaded times before saving them (up to 1m)
SCHEDULER_UNHEALTHY_THRESHOLD3Consecutive failures before marking unhealthy
SCHEDULER_SHUTDOWN_GRACE_PERIOD30sTime to wait for running jobs during server restart
API_TOKEN_RETENTION_DAYS90Default retention for expired API tokens

14. FAQ

Q: Can I add custom jobs? A: Custom jobs are added by developers through the codebase. The scheduler UI manages existing registered jobs. If you need a new recurring task, contact your development team.

Q: What happens during a server restart? A: Running jobs are given a grace period to complete (default: 30 seconds). If they don't finish in time, they are cancelled and recorded as "timeout". On the next startup, the scheduler detects any missed fire times and handles them according to each job's misfire policy.

Q: Can I see which node ran a job? A: Yes — the run history shows the Node ID for each execution. This is useful for debugging in multi-node deployments.

Q: What timezone do schedules use? A: All cron schedules use UTC, whatever time zone the servers or viewers are in. Last and next run times, and the next run shown while you edit a schedule, are in your own time zone.

Q: Will disabling a job cause data to accumulate? A: Yes — if you disable a cleanup job, the data it would normally clean up will continue to grow. Only disable jobs temporarily and re-enable them when the issue is resolved.