feat: queues (#24142)

This commit is contained in:
Jason Rasmussen
2025-11-25 08:19:40 -05:00
committed by GitHub
parent 66ae07ee39
commit 104fa09f69
37 changed files with 2487 additions and 336 deletions

View File

@@ -4929,6 +4929,7 @@
},
"/jobs": {
"get": {
"deprecated": true,
"description": "Retrieve the counts of the current queue, as well as the current status.",
"operationId": "getQueuesLegacy",
"parameters": [],
@@ -4937,7 +4938,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueuesResponseDto"
"$ref": "#/components/schemas/QueuesResponseLegacyDto"
}
}
},
@@ -4957,7 +4958,8 @@
],
"summary": "Retrieve queue counts and status",
"tags": [
"Jobs"
"Jobs",
"Deprecated"
],
"x-immich-admin-only": true,
"x-immich-history": [
@@ -4972,10 +4974,14 @@
{
"version": "v2",
"state": "Stable"
},
{
"version": "v2.4.0",
"state": "Deprecated"
}
],
"x-immich-permission": "job.read",
"x-immich-state": "Stable"
"x-immich-state": "Deprecated"
},
"post": {
"description": "Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.",
@@ -5032,6 +5038,7 @@
},
"/jobs/{name}": {
"put": {
"deprecated": true,
"description": "Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.",
"operationId": "runQueueCommandLegacy",
"parameters": [
@@ -5059,7 +5066,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
}
}
},
@@ -5079,7 +5086,8 @@
],
"summary": "Run jobs",
"tags": [
"Jobs"
"Jobs",
"Deprecated"
],
"x-immich-admin-only": true,
"x-immich-history": [
@@ -5094,10 +5102,14 @@
{
"version": "v2",
"state": "Stable"
},
{
"version": "v2.4.0",
"state": "Deprecated"
}
],
"x-immich-permission": "job.create",
"x-immich-state": "Stable"
"x-immich-state": "Deprecated"
}
},
"/libraries": {
@@ -8064,6 +8076,303 @@
"x-immich-state": "Alpha"
}
},
"/queues": {
"get": {
"description": "Retrieves a list of queues.",
"operationId": "getQueues",
"parameters": [],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/QueueResponseDto"
},
"type": "array"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "List all queues",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-permission": "queue.read",
"x-immich-state": "Alpha"
}
},
"/queues/{name}": {
"get": {
"description": "Retrieves a specific queue by its name.",
"operationId": "getQueue",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"schema": {
"$ref": "#/components/schemas/QueueName"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Retrieve a queue",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-permission": "queue.read",
"x-immich-state": "Alpha"
},
"put": {
"description": "Change the paused status of a specific queue.",
"operationId": "updateQueue",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"schema": {
"$ref": "#/components/schemas/QueueName"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueUpdateDto"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Update a queue",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-permission": "queue.update",
"x-immich-state": "Alpha"
}
},
"/queues/{name}/jobs": {
"delete": {
"description": "Removes all jobs from the specified queue.",
"operationId": "emptyQueue",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"schema": {
"$ref": "#/components/schemas/QueueName"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueDeleteDto"
}
}
},
"required": true
},
"responses": {
"204": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Empty a queue",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-permission": "queueJob.delete",
"x-immich-state": "Alpha"
},
"get": {
"description": "Retrieves a list of queue jobs from the specified queue.",
"operationId": "getQueueJobs",
"parameters": [
{
"name": "name",
"required": true,
"in": "path",
"schema": {
"$ref": "#/components/schemas/QueueName"
}
},
{
"name": "status",
"required": false,
"in": "query",
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/QueueJobStatus"
}
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/QueueJobResponseDto"
},
"type": "array"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Retrieve queue jobs",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-permission": "queueJob.read",
"x-immich-state": "Alpha"
}
},
"/search/cities": {
"get": {
"description": "Retrieve a list of assets with each asset belonging to a different city. This endpoint is used on the places pages to show a single thumbnail for each city the user has assets in.",
@@ -14043,6 +14352,10 @@
"name": "Plugins",
"description": "A plugin is an installed module that makes filters and actions available for the workflow feature."
},
{
"name": "Queues",
"description": "Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed."
},
{
"name": "Search",
"description": "Endpoints related to searching assets via text, smart search, optical character recognition (OCR), and other filters like person, album, and other metadata. Search endpoints usually support pagination and sorting."
@@ -16291,6 +16604,66 @@
],
"type": "object"
},
"JobName": {
"enum": [
"AssetDelete",
"AssetDeleteCheck",
"AssetDetectFacesQueueAll",
"AssetDetectFaces",
"AssetDetectDuplicatesQueueAll",
"AssetDetectDuplicates",
"AssetEncodeVideoQueueAll",
"AssetEncodeVideo",
"AssetEmptyTrash",
"AssetExtractMetadataQueueAll",
"AssetExtractMetadata",
"AssetFileMigration",
"AssetGenerateThumbnailsQueueAll",
"AssetGenerateThumbnails",
"AuditLogCleanup",
"AuditTableCleanup",
"DatabaseBackup",
"FacialRecognitionQueueAll",
"FacialRecognition",
"FileDelete",
"FileMigrationQueueAll",
"LibraryDeleteCheck",
"LibraryDelete",
"LibraryRemoveAsset",
"LibraryScanAssetsQueueAll",
"LibrarySyncAssets",
"LibrarySyncFilesQueueAll",
"LibrarySyncFiles",
"LibraryScanQueueAll",
"MemoryCleanup",
"MemoryGenerate",
"NotificationsCleanup",
"NotifyUserSignup",
"NotifyAlbumInvite",
"NotifyAlbumUpdate",
"UserDelete",
"UserDeleteCheck",
"UserSyncUsage",
"PersonCleanup",
"PersonFileMigration",
"PersonGenerateThumbnail",
"SessionCleanup",
"SendMail",
"SidecarQueueAll",
"SidecarCheck",
"SidecarWrite",
"SmartSearchQueueAll",
"SmartSearch",
"StorageTemplateMigration",
"StorageTemplateMigrationSingle",
"TagCleanup",
"VersionCheck",
"OcrQueueAll",
"Ocr",
"WorkflowRun"
],
"type": "string"
},
"JobSettingsDto": {
"properties": {
"concurrency": {
@@ -17583,6 +17956,12 @@
"userProfileImage.read",
"userProfileImage.update",
"userProfileImage.delete",
"queue.read",
"queue.update",
"queueJob.create",
"queueJob.read",
"queueJob.update",
"queueJob.delete",
"workflow.create",
"workflow.read",
"workflow.update",
@@ -18083,6 +18462,63 @@
],
"type": "object"
},
"QueueDeleteDto": {
"properties": {
"failed": {
"description": "If true, will also remove failed jobs from the queue.",
"type": "boolean",
"x-immich-history": [
{
"version": "v2.4.0",
"state": "Added"
},
{
"version": "v2.4.0",
"state": "Alpha"
}
],
"x-immich-state": "Alpha"
}
},
"type": "object"
},
"QueueJobResponseDto": {
"properties": {
"data": {
"type": "object"
},
"id": {
"type": "string"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/JobName"
}
]
},
"timestamp": {
"type": "integer"
}
},
"required": [
"data",
"name",
"timestamp"
],
"type": "object"
},
"QueueJobStatus": {
"enum": [
"active",
"failed",
"completed",
"delayed",
"waiting",
"paused"
],
"type": "string"
},
"QueueName": {
"enum": [
"thumbnailGeneration",
@@ -18106,12 +18542,35 @@
"type": "string"
},
"QueueResponseDto": {
"properties": {
"isPaused": {
"type": "boolean"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/QueueName"
}
]
},
"statistics": {
"$ref": "#/components/schemas/QueueStatisticsDto"
}
},
"required": [
"isPaused",
"name",
"statistics"
],
"type": "object"
},
"QueueResponseLegacyDto": {
"properties": {
"jobCounts": {
"$ref": "#/components/schemas/QueueStatisticsDto"
},
"queueStatus": {
"$ref": "#/components/schemas/QueueStatusDto"
"$ref": "#/components/schemas/QueueStatusLegacyDto"
}
},
"required": [
@@ -18151,7 +18610,7 @@
],
"type": "object"
},
"QueueStatusDto": {
"QueueStatusLegacyDto": {
"properties": {
"isActive": {
"type": "boolean"
@@ -18166,58 +18625,66 @@
],
"type": "object"
},
"QueuesResponseDto": {
"QueueUpdateDto": {
"properties": {
"isPaused": {
"type": "boolean"
}
},
"type": "object"
},
"QueuesResponseLegacyDto": {
"properties": {
"backgroundTask": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"backupDatabase": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"duplicateDetection": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"faceDetection": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"facialRecognition": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"library": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"metadataExtraction": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"migration": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"notifications": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"ocr": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"search": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"sidecar": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"smartSearch": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"storageTemplateMigration": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"thumbnailGeneration": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"videoConversion": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
},
"workflow": {
"$ref": "#/components/schemas/QueueResponseDto"
"$ref": "#/components/schemas/QueueResponseLegacyDto"
}
},
"required": [

View File

@@ -716,32 +716,32 @@ export type QueueStatisticsDto = {
paused: number;
waiting: number;
};
export type QueueStatusDto = {
export type QueueStatusLegacyDto = {
isActive: boolean;
isPaused: boolean;
};
export type QueueResponseDto = {
export type QueueResponseLegacyDto = {
jobCounts: QueueStatisticsDto;
queueStatus: QueueStatusDto;
queueStatus: QueueStatusLegacyDto;
};
export type QueuesResponseDto = {
backgroundTask: QueueResponseDto;
backupDatabase: QueueResponseDto;
duplicateDetection: QueueResponseDto;
faceDetection: QueueResponseDto;
facialRecognition: QueueResponseDto;
library: QueueResponseDto;
metadataExtraction: QueueResponseDto;
migration: QueueResponseDto;
notifications: QueueResponseDto;
ocr: QueueResponseDto;
search: QueueResponseDto;
sidecar: QueueResponseDto;
smartSearch: QueueResponseDto;
storageTemplateMigration: QueueResponseDto;
thumbnailGeneration: QueueResponseDto;
videoConversion: QueueResponseDto;
workflow: QueueResponseDto;
export type QueuesResponseLegacyDto = {
backgroundTask: QueueResponseLegacyDto;
backupDatabase: QueueResponseLegacyDto;
duplicateDetection: QueueResponseLegacyDto;
faceDetection: QueueResponseLegacyDto;
facialRecognition: QueueResponseLegacyDto;
library: QueueResponseLegacyDto;
metadataExtraction: QueueResponseLegacyDto;
migration: QueueResponseLegacyDto;
notifications: QueueResponseLegacyDto;
ocr: QueueResponseLegacyDto;
search: QueueResponseLegacyDto;
sidecar: QueueResponseLegacyDto;
smartSearch: QueueResponseLegacyDto;
storageTemplateMigration: QueueResponseLegacyDto;
thumbnailGeneration: QueueResponseLegacyDto;
videoConversion: QueueResponseLegacyDto;
workflow: QueueResponseLegacyDto;
};
export type JobCreateDto = {
name: ManualJobName;
@@ -966,6 +966,24 @@ export type PluginResponseDto = {
updatedAt: string;
version: string;
};
export type QueueResponseDto = {
isPaused: boolean;
name: QueueName;
statistics: QueueStatisticsDto;
};
export type QueueUpdateDto = {
isPaused?: boolean;
};
export type QueueDeleteDto = {
/** If true, will also remove failed jobs from the queue. */
failed?: boolean;
};
export type QueueJobResponseDto = {
data: object;
id?: string;
name: JobName;
timestamp: number;
};
export type SearchExploreItem = {
data: AssetResponseDto;
value: string;
@@ -2925,7 +2943,7 @@ export function reassignFacesById({ id, faceDto }: {
export function getQueuesLegacy(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueuesResponseDto;
data: QueuesResponseLegacyDto;
}>("/jobs", {
...opts
}));
@@ -2951,7 +2969,7 @@ export function runQueueCommandLegacy({ name, queueCommandDto }: {
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueueResponseDto;
data: QueueResponseLegacyDto;
}>(`/jobs/${encodeURIComponent(name)}`, oazapfts.json({
...opts,
method: "PUT",
@@ -3651,6 +3669,75 @@ export function getPlugin({ id }: {
...opts
}));
}
/**
* List all queues
*/
export function getQueues(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueueResponseDto[];
}>("/queues", {
...opts
}));
}
/**
* Retrieve a queue
*/
export function getQueue({ name }: {
name: QueueName;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueueResponseDto;
}>(`/queues/${encodeURIComponent(name)}`, {
...opts
}));
}
/**
* Update a queue
*/
export function updateQueue({ name, queueUpdateDto }: {
name: QueueName;
queueUpdateDto: QueueUpdateDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueueResponseDto;
}>(`/queues/${encodeURIComponent(name)}`, oazapfts.json({
...opts,
method: "PUT",
body: queueUpdateDto
})));
}
/**
* Empty a queue
*/
export function emptyQueue({ name, queueDeleteDto }: {
name: QueueName;
queueDeleteDto: QueueDeleteDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText(`/queues/${encodeURIComponent(name)}/jobs`, oazapfts.json({
...opts,
method: "DELETE",
body: queueDeleteDto
})));
}
/**
* Retrieve queue jobs
*/
export function getQueueJobs({ name, status }: {
name: QueueName;
status?: QueueJobStatus[];
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: QueueJobResponseDto[];
}>(`/queues/${encodeURIComponent(name)}/jobs${QS.query(QS.explode({
status
}))}`, {
...opts
}));
}
/**
* Retrieve assets by city
*/
@@ -5241,6 +5328,12 @@ export enum Permission {
UserProfileImageRead = "userProfileImage.read",
UserProfileImageUpdate = "userProfileImage.update",
UserProfileImageDelete = "userProfileImage.delete",
QueueRead = "queue.read",
QueueUpdate = "queue.update",
QueueJobCreate = "queueJob.create",
QueueJobRead = "queueJob.read",
QueueJobUpdate = "queueJob.update",
QueueJobDelete = "queueJob.delete",
WorkflowCreate = "workflow.create",
WorkflowRead = "workflow.read",
WorkflowUpdate = "workflow.update",
@@ -5330,6 +5423,71 @@ export enum PluginContext {
Album = "album",
Person = "person"
}
export enum QueueJobStatus {
Active = "active",
Failed = "failed",
Completed = "completed",
Delayed = "delayed",
Waiting = "waiting",
Paused = "paused"
}
export enum JobName {
AssetDelete = "AssetDelete",
AssetDeleteCheck = "AssetDeleteCheck",
AssetDetectFacesQueueAll = "AssetDetectFacesQueueAll",
AssetDetectFaces = "AssetDetectFaces",
AssetDetectDuplicatesQueueAll = "AssetDetectDuplicatesQueueAll",
AssetDetectDuplicates = "AssetDetectDuplicates",
AssetEncodeVideoQueueAll = "AssetEncodeVideoQueueAll",
AssetEncodeVideo = "AssetEncodeVideo",
AssetEmptyTrash = "AssetEmptyTrash",
AssetExtractMetadataQueueAll = "AssetExtractMetadataQueueAll",
AssetExtractMetadata = "AssetExtractMetadata",
AssetFileMigration = "AssetFileMigration",
AssetGenerateThumbnailsQueueAll = "AssetGenerateThumbnailsQueueAll",
AssetGenerateThumbnails = "AssetGenerateThumbnails",
AuditLogCleanup = "AuditLogCleanup",
AuditTableCleanup = "AuditTableCleanup",
DatabaseBackup = "DatabaseBackup",
FacialRecognitionQueueAll = "FacialRecognitionQueueAll",
FacialRecognition = "FacialRecognition",
FileDelete = "FileDelete",
FileMigrationQueueAll = "FileMigrationQueueAll",
LibraryDeleteCheck = "LibraryDeleteCheck",
LibraryDelete = "LibraryDelete",
LibraryRemoveAsset = "LibraryRemoveAsset",
LibraryScanAssetsQueueAll = "LibraryScanAssetsQueueAll",
LibrarySyncAssets = "LibrarySyncAssets",
LibrarySyncFilesQueueAll = "LibrarySyncFilesQueueAll",
LibrarySyncFiles = "LibrarySyncFiles",
LibraryScanQueueAll = "LibraryScanQueueAll",
MemoryCleanup = "MemoryCleanup",
MemoryGenerate = "MemoryGenerate",
NotificationsCleanup = "NotificationsCleanup",
NotifyUserSignup = "NotifyUserSignup",
NotifyAlbumInvite = "NotifyAlbumInvite",
NotifyAlbumUpdate = "NotifyAlbumUpdate",
UserDelete = "UserDelete",
UserDeleteCheck = "UserDeleteCheck",
UserSyncUsage = "UserSyncUsage",
PersonCleanup = "PersonCleanup",
PersonFileMigration = "PersonFileMigration",
PersonGenerateThumbnail = "PersonGenerateThumbnail",
SessionCleanup = "SessionCleanup",
SendMail = "SendMail",
SidecarQueueAll = "SidecarQueueAll",
SidecarCheck = "SidecarCheck",
SidecarWrite = "SidecarWrite",
SmartSearchQueueAll = "SmartSearchQueueAll",
SmartSearch = "SmartSearch",
StorageTemplateMigration = "StorageTemplateMigration",
StorageTemplateMigrationSingle = "StorageTemplateMigrationSingle",
TagCleanup = "TagCleanup",
VersionCheck = "VersionCheck",
OcrQueueAll = "OcrQueueAll",
Ocr = "Ocr",
WorkflowRun = "WorkflowRun"
}
export enum SearchSuggestionType {
Country = "country",
State = "state",