refactor: job names (#19949)

This commit is contained in:
Jason Rasmussen 2025-07-15 18:39:00 -04:00 committed by GitHub
parent e73abe0762
commit bcb968e3d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 334 additions and 343 deletions

View File

@ -441,94 +441,75 @@ export enum QueueName {
} }
export enum JobName { export enum JobName {
//backups AssetDelete = 'AssetDelete',
BackupDatabase = 'database-backup', 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',
// conversion AuditLogCleanup = 'AuditLogCleanup',
QueueVideoConversion = 'queue-video-conversion',
VideoConversation = 'video-conversion',
// thumbnails DatabaseBackup = 'DatabaseBackup',
QueueGenerateThumbnails = 'queue-generate-thumbnails',
GenerateThumbnails = 'generate-thumbnails',
GeneratePersonThumbnail = 'generate-person-thumbnail',
// metadata FacialRecognitionQueueAll = 'FacialRecognitionQueueAll',
QueueMetadataExtraction = 'queue-metadata-extraction', FacialRecognition = 'FacialRecognition',
MetadataExtraction = 'metadata-extraction',
// user FileDelete = 'FileDelete',
UserDeletion = 'user-deletion', FileMigrationQueueAll = 'FileMigrationQueueAll',
UserDeleteCheck = 'user-delete-check',
userSyncUsage = 'user-sync-usage',
// asset LibraryDeleteCheck = 'LibraryDeleteCheck',
AssetDeletion = 'asset-deletion', LibraryDelete = 'LibraryDelete',
AssetDeletionCheck = 'asset-deletion-check', LibraryRemoveAsset = 'LibraryRemoveAsset',
LibrarySyncAssetsQueueAll = 'LibraryScanAssetsQueueAll',
LibrarySyncAssets = 'LibrarySyncAssets',
LibrarySyncFilesQueueAll = 'LibrarySyncFilesQueueAll',
LibrarySyncFiles = 'LibrarySyncFiles',
LibraryScanQueueAll = 'LibraryScanQueueAll',
// storage template MemoryCleanup = 'MemoryCleanup',
StorageTemplateMigration = 'storage-template-migration', MemoryGenerate = 'MemoryGenerate',
StorageTemplateMigrationSingle = 'storage-template-migration-single',
// tags NotificationsCleanup = 'NotificationsCleanup',
TagCleanup = 'tag-cleanup',
// migration NotifyUserSignup = 'NotifyUserSignup',
QueueMigration = 'queue-migration', NotifyAlbumInvite = 'NotifyAlbumInvite',
MigrateAsset = 'migrate-asset', NotifyAlbumUpdate = 'NotifyAlbumUpdate',
MigratePerson = 'migrate-person',
// facial recognition UserDelete = 'UserDelete',
PersonCleanup = 'person-cleanup', UserDeleteCheck = 'UserDeleteCheck',
QueueFaceDetection = 'queue-face-detection', UserSyncUsage = 'UserSyncUsage',
FaceDetection = 'face-detection',
QueueFacialRecognition = 'queue-facial-recognition',
FacialRecognition = 'facial-recognition',
// library management PersonCleanup = 'PersonCleanup',
LibraryQueueSyncFiles = 'library-queue-sync-files', PersonFileMigration = 'PersonFileMigration',
LibraryQueueSyncAssets = 'library-queue-sync-assets', PersonGenerateThumbnail = 'PersonGenerateThumbnail',
LibrarySyncFiles = 'library-sync-files',
LibrarySyncAssets = 'library-sync-assets',
LibraryAssetRemoval = 'handle-library-file-deletion',
LibraryDelete = 'library-delete',
LibraryQueueScanAll = 'library-queue-scan-all',
LibraryQueueCleanup = 'library-queue-cleanup',
// cleanup SessionCleanup = 'SessionCleanup',
DeleteFiles = 'delete-files',
CleanOldAuditLogs = 'clean-old-audit-logs',
CleanOldSessionTokens = 'clean-old-session-tokens',
// memories SendMail = 'SendMail',
MemoriesCleanup = 'memories-cleanup',
MemoriesCreate = 'memories-create',
// smart search SidecarQueueAll = 'SidecarQueueAll',
QueueSmartSearch = 'queue-smart-search', SidecarDiscovery = 'SidecarDiscovery',
SmartSearch = 'smart-search', SidecarSync = 'SidecarSync',
SidecarWrite = 'SidecarWrite',
QueueTrashEmpty = 'queue-trash-empty', SmartSearchQueueAll = 'SmartSearchQueueAll',
SmartSearch = 'SmartSearch',
// duplicate detection StorageTemplateMigration = 'StorageTemplateMigration',
QueueDuplicateDetection = 'queue-duplicate-detection', StorageTemplateMigrationSingle = 'StorageTemplateMigrationSingle',
DuplicateDetection = 'duplicate-detection',
// XMP sidecars TagCleanup = 'TagCleanup',
QueueSidecar = 'queue-sidecar',
SidecarDiscovery = 'sidecar-discovery',
SidecarSync = 'sidecar-sync',
SidecarWrite = 'sidecar-write',
// Notification VersionCheck = 'VersionCheck',
NotifySignup = 'notify-signup',
NotifyAlbumInvite = 'notify-album-invite',
NotifyAlbumUpdate = 'notify-album-update',
NotificationsCleanup = 'notifications-cleanup',
SendMail = 'notification-send-email',
// Version check
VersionCheck = 'version-check',
} }
export enum JobCommand { export enum JobCommand {

View File

@ -214,11 +214,11 @@ export class JobRepository {
case JobName.StorageTemplateMigrationSingle: { case JobName.StorageTemplateMigrationSingle: {
return { jobId: item.data.id }; return { jobId: item.data.id };
} }
case JobName.GeneratePersonThumbnail: { case JobName.PersonGenerateThumbnail: {
return { priority: 1 }; return { priority: 1 };
} }
case JobName.QueueFacialRecognition: { case JobName.FacialRecognitionQueueAll: {
return { jobId: JobName.QueueFacialRecognition }; return { jobId: JobName.FacialRecognitionQueueAll };
} }
default: { default: {
return null; return null;

View File

@ -384,7 +384,7 @@ describe(AssetMediaService.name, () => {
}); });
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: ['fake_path/asset_1.jpeg', undefined] }, data: { files: ['fake_path/asset_1.jpeg', undefined] },
}); });
expect(mocks.user.updateUsage).not.toHaveBeenCalled(); expect(mocks.user.updateUsage).not.toHaveBeenCalled();
@ -409,7 +409,7 @@ describe(AssetMediaService.name, () => {
); );
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: ['fake_path/asset_1.jpeg', undefined] }, data: { files: ['fake_path/asset_1.jpeg', undefined] },
}); });
expect(mocks.user.updateUsage).not.toHaveBeenCalled(); expect(mocks.user.updateUsage).not.toHaveBeenCalled();
@ -815,7 +815,7 @@ describe(AssetMediaService.name, () => {
expect(mocks.asset.create).not.toHaveBeenCalled(); expect(mocks.asset.create).not.toHaveBeenCalled();
expect(mocks.asset.updateAll).not.toHaveBeenCalled(); expect(mocks.asset.updateAll).not.toHaveBeenCalled();
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: [updatedFile.originalPath, undefined] }, data: { files: [updatedFile.originalPath, undefined] },
}); });
expect(mocks.user.updateUsage).not.toHaveBeenCalled(); expect(mocks.user.updateUsage).not.toHaveBeenCalled();
@ -912,7 +912,7 @@ describe(AssetMediaService.name, () => {
await sut.onUploadError(request, file); await sut.onUploadError(request, file);
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: ['upload/upload/user-id/ra/nd/random-uuid.jpg'] }, data: { files: ['upload/upload/user-id/ra/nd/random-uuid.jpg'] },
}); });
}); });

View File

@ -121,7 +121,7 @@ export class AssetMediaService extends BaseService {
const uploadFolder = this.getUploadFolder(asRequest(request, file)); const uploadFolder = this.getUploadFolder(asRequest(request, file));
const uploadPath = `${uploadFolder}/${uploadFilename}`; const uploadPath = `${uploadFolder}/${uploadFilename}`;
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files: [uploadPath] } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [uploadPath] } });
} }
async uploadAsset( async uploadAsset(
@ -312,7 +312,7 @@ export class AssetMediaService extends BaseService {
): Promise<AssetMediaResponseDto> { ): Promise<AssetMediaResponseDto> {
// clean up files // clean up files
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: [file.originalPath, sidecarFile?.originalPath] }, data: { files: [file.originalPath, sidecarFile?.originalPath] },
}); });
@ -365,7 +365,7 @@ export class AssetMediaService extends BaseService {
await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt)); await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt));
await this.assetRepository.upsertExif({ assetId, fileSizeInByte: file.size }); await this.assetRepository.upsertExif({ assetId, fileSizeInByte: file.size });
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.MetadataExtraction, name: JobName.AssetExtractMetadata,
data: { id: assetId, source: 'upload' }, data: { id: assetId, source: 'upload' },
}); });
} }
@ -394,7 +394,7 @@ export class AssetMediaService extends BaseService {
const { size } = await this.storageRepository.stat(created.originalPath); const { size } = await this.storageRepository.stat(created.originalPath);
await this.assetRepository.upsertExif({ assetId: created.id, fileSizeInByte: size }); await this.assetRepository.upsertExif({ assetId: created.id, fileSizeInByte: size });
await this.jobRepository.queue({ name: JobName.MetadataExtraction, data: { id: created.id, source: 'copy' } }); await this.jobRepository.queue({ name: JobName.AssetExtractMetadata, data: { id: created.id, source: 'copy' } });
return created; return created;
} }
@ -427,7 +427,7 @@ export class AssetMediaService extends BaseService {
} }
await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt)); await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt));
await this.assetRepository.upsertExif({ assetId: asset.id, fileSizeInByte: file.size }); await this.assetRepository.upsertExif({ assetId: asset.id, fileSizeInByte: file.size });
await this.jobRepository.queue({ name: JobName.MetadataExtraction, data: { id: asset.id, source: 'upload' } }); await this.jobRepository.queue({ name: JobName.AssetExtractMetadata, data: { id: asset.id, source: 'upload' } });
return asset; return asset;
} }

View File

@ -522,7 +522,7 @@ describe(AssetService.name, () => {
expect(mocks.assetJob.streamForDeletedJob).toHaveBeenCalledWith(new Date()); expect(mocks.assetJob.streamForDeletedJob).toHaveBeenCalledWith(new Date());
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.AssetDeletion, data: { id: asset.id, deleteOnDisk: true } }, { name: JobName.AssetDelete, data: { id: asset.id, deleteOnDisk: true } },
]); ]);
}); });
@ -536,7 +536,7 @@ describe(AssetService.name, () => {
expect(mocks.assetJob.streamForDeletedJob).toHaveBeenCalledWith(DateTime.now().minus({ days: 7 }).toJSDate()); expect(mocks.assetJob.streamForDeletedJob).toHaveBeenCalledWith(DateTime.now().minus({ days: 7 }).toJSDate());
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.AssetDeletion, data: { id: asset.id, deleteOnDisk: true } }, { name: JobName.AssetDelete, data: { id: asset.id, deleteOnDisk: true } },
]); ]);
}); });
}); });
@ -552,7 +552,7 @@ describe(AssetService.name, () => {
expect(mocks.job.queue.mock.calls).toEqual([ expect(mocks.job.queue.mock.calls).toEqual([
[ [
{ {
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { data: {
files: [ files: [
'/uploads/user-id/webp/path.ext', '/uploads/user-id/webp/path.ext',
@ -606,7 +606,7 @@ describe(AssetService.name, () => {
expect(mocks.job.queue.mock.calls).toEqual([ expect(mocks.job.queue.mock.calls).toEqual([
[ [
{ {
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { data: {
id: assetStub.livePhotoMotionAsset.id, id: assetStub.livePhotoMotionAsset.id,
deleteOnDisk: true, deleteOnDisk: true,
@ -615,7 +615,7 @@ describe(AssetService.name, () => {
], ],
[ [
{ {
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { data: {
files: [ files: [
'/uploads/user-id/webp/path.ext', '/uploads/user-id/webp/path.ext',
@ -643,7 +643,7 @@ describe(AssetService.name, () => {
expect(mocks.job.queue.mock.calls).toEqual([ expect(mocks.job.queue.mock.calls).toEqual([
[ [
{ {
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { data: {
files: [ files: [
'/uploads/user-id/webp/path.ext', '/uploads/user-id/webp/path.ext',
@ -679,7 +679,7 @@ describe(AssetService.name, () => {
await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REFRESH_FACES }); await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REFRESH_FACES });
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.FaceDetection, data: { id: 'asset-1' } }]); expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.AssetDetectFaces, data: { id: 'asset-1' } }]);
}); });
it('should run the refresh metadata job', async () => { it('should run the refresh metadata job', async () => {
@ -687,7 +687,9 @@ describe(AssetService.name, () => {
await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REFRESH_METADATA }); await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REFRESH_METADATA });
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.MetadataExtraction, data: { id: 'asset-1' } }]); expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.AssetExtractMetadata, data: { id: 'asset-1' } },
]);
}); });
it('should run the refresh thumbnails job', async () => { it('should run the refresh thumbnails job', async () => {
@ -695,7 +697,9 @@ describe(AssetService.name, () => {
await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REGENERATE_THUMBNAIL }); await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.REGENERATE_THUMBNAIL });
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.GenerateThumbnails, data: { id: 'asset-1' } }]); expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.AssetGenerateThumbnails, data: { id: 'asset-1' } },
]);
}); });
it('should run the transcode video', async () => { it('should run the transcode video', async () => {
@ -703,7 +707,7 @@ describe(AssetService.name, () => {
await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.TRANSCODE_VIDEO }); await sut.run(authStub.admin, { assetIds: ['asset-1'], name: AssetJobName.TRANSCODE_VIDEO });
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.VideoConversation, data: { id: 'asset-1' } }]); expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.AssetEncodeVideo, data: { id: 'asset-1' } }]);
}); });
}); });

View File

@ -145,7 +145,7 @@ export class AssetService extends BaseService {
} }
} }
@OnJob({ name: JobName.AssetDeletionCheck, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.AssetDeleteCheck, queue: QueueName.BackgroundTask })
async handleAssetDeletionCheck(): Promise<JobStatus> { async handleAssetDeletionCheck(): Promise<JobStatus> {
const config = await this.getConfig({ withCache: false }); const config = await this.getConfig({ withCache: false });
const trashedDays = config.trash.enabled ? config.trash.days : 0; const trashedDays = config.trash.enabled ? config.trash.days : 0;
@ -158,7 +158,7 @@ export class AssetService extends BaseService {
if (chunk.length > 0) { if (chunk.length > 0) {
await this.jobRepository.queueAll( await this.jobRepository.queueAll(
chunk.map(({ id, isOffline }) => ({ chunk.map(({ id, isOffline }) => ({
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { id, deleteOnDisk: !isOffline }, data: { id, deleteOnDisk: !isOffline },
})), })),
); );
@ -179,8 +179,8 @@ export class AssetService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.AssetDeletion, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.AssetDelete, queue: QueueName.BackgroundTask })
async handleAssetDeletion(job: JobOf<JobName.AssetDeletion>): Promise<JobStatus> { async handleAssetDeletion(job: JobOf<JobName.AssetDelete>): Promise<JobStatus> {
const { id, deleteOnDisk } = job; const { id, deleteOnDisk } = job;
const asset = await this.assetJobRepository.getForAssetDeletion(id); const asset = await this.assetJobRepository.getForAssetDeletion(id);
@ -215,7 +215,7 @@ export class AssetService extends BaseService {
const count = await this.assetRepository.getLivePhotoCount(asset.livePhotoVideoId); const count = await this.assetRepository.getLivePhotoCount(asset.livePhotoVideoId);
if (count === 0) { if (count === 0) {
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { id: asset.livePhotoVideoId, deleteOnDisk }, data: { id: asset.livePhotoVideoId, deleteOnDisk },
}); });
} }
@ -228,7 +228,7 @@ export class AssetService extends BaseService {
files.push(asset.sidecarPath, asset.originalPath); files.push(asset.sidecarPath, asset.originalPath);
} }
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files } });
return JobStatus.Success; return JobStatus.Success;
} }
@ -255,22 +255,22 @@ export class AssetService extends BaseService {
for (const id of dto.assetIds) { for (const id of dto.assetIds) {
switch (dto.name) { switch (dto.name) {
case AssetJobName.REFRESH_FACES: { case AssetJobName.REFRESH_FACES: {
jobs.push({ name: JobName.FaceDetection, data: { id } }); jobs.push({ name: JobName.AssetDetectFaces, data: { id } });
break; break;
} }
case AssetJobName.REFRESH_METADATA: { case AssetJobName.REFRESH_METADATA: {
jobs.push({ name: JobName.MetadataExtraction, data: { id } }); jobs.push({ name: JobName.AssetExtractMetadata, data: { id } });
break; break;
} }
case AssetJobName.REGENERATE_THUMBNAIL: { case AssetJobName.REGENERATE_THUMBNAIL: {
jobs.push({ name: JobName.GenerateThumbnails, data: { id } }); jobs.push({ name: JobName.AssetGenerateThumbnails, data: { id } });
break; break;
} }
case AssetJobName.TRANSCODE_VIDEO: { case AssetJobName.TRANSCODE_VIDEO: {
jobs.push({ name: JobName.VideoConversation, data: { id } }); jobs.push({ name: JobName.AssetEncodeVideo, data: { id } });
break; break;
} }
} }

View File

@ -7,7 +7,7 @@ import { BaseService } from 'src/services/base.service';
@Injectable() @Injectable()
export class AuditService extends BaseService { export class AuditService extends BaseService {
@OnJob({ name: JobName.CleanOldAuditLogs, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.AuditLogCleanup, queue: QueueName.BackgroundTask })
async handleCleanup(): Promise<JobStatus> { async handleCleanup(): Promise<JobStatus> {
await this.auditRepository.removeBefore(DateTime.now().minus(AUDIT_LOG_MAX_DURATION).toJSDate()); await this.auditRepository.removeBefore(DateTime.now().minus(AUDIT_LOG_MAX_DURATION).toJSDate());
return JobStatus.Success; return JobStatus.Success;

View File

@ -330,7 +330,7 @@ export class AuthService extends BaseService {
await this.userRepository.update(user.id, { profileImagePath, profileChangedAt: new Date() }); await this.userRepository.update(user.id, { profileImagePath, profileChangedAt: new Date() });
if (oldPath) { if (oldPath) {
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files: [oldPath] } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [oldPath] } });
} }
} catch (error: Error | any) { } catch (error: Error | any) {
this.logger.warn(`Unable to sync oauth profile picture: ${error}`, error?.stack); this.logger.warn(`Unable to sync oauth profile picture: ${error}`, error?.stack);

View File

@ -26,7 +26,7 @@ export class BackupService extends BaseService {
this.cronRepository.create({ this.cronRepository.create({
name: 'backupDatabase', name: 'backupDatabase',
expression: database.cronExpression, expression: database.cronExpression,
onTick: () => handlePromiseError(this.jobRepository.queue({ name: JobName.BackupDatabase }), this.logger), onTick: () => handlePromiseError(this.jobRepository.queue({ name: JobName.DatabaseBackup }), this.logger),
start: database.enabled, start: database.enabled,
}); });
} }
@ -68,7 +68,7 @@ export class BackupService extends BaseService {
this.logger.debug(`Database Backup Cleanup Finished, deleted ${toDelete.length} backups`); this.logger.debug(`Database Backup Cleanup Finished, deleted ${toDelete.length} backups`);
} }
@OnJob({ name: JobName.BackupDatabase, queue: QueueName.BackupDatabase }) @OnJob({ name: JobName.DatabaseBackup, queue: QueueName.BackupDatabase })
async handleBackupDatabase(): Promise<JobStatus> { async handleBackupDatabase(): Promise<JobStatus> {
this.logger.debug(`Database Backup Started`); this.logger.debug(`Database Backup Started`);
const { database } = this.configRepository.getEnv(); const { database } = this.configRepository.getEnv();

View File

@ -108,7 +108,7 @@ describe(SearchService.name, () => {
expect(mocks.assetJob.streamForSearchDuplicates).toHaveBeenCalledWith(undefined); expect(mocks.assetJob.streamForSearchDuplicates).toHaveBeenCalledWith(undefined);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.DuplicateDetection, name: JobName.AssetDetectDuplicates,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -122,7 +122,7 @@ describe(SearchService.name, () => {
expect(mocks.assetJob.streamForSearchDuplicates).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForSearchDuplicates).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.DuplicateDetection, name: JobName.AssetDetectDuplicates,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);

View File

@ -29,8 +29,8 @@ export class DuplicateService extends BaseService {
await this.duplicateRepository.deleteAll(auth.user.id, dto.ids); await this.duplicateRepository.deleteAll(auth.user.id, dto.ids);
} }
@OnJob({ name: JobName.QueueDuplicateDetection, queue: QueueName.DuplicateDetection }) @OnJob({ name: JobName.AssetDetectDuplicatesQueueAll, queue: QueueName.DuplicateDetection })
async handleQueueSearchDuplicates({ force }: JobOf<JobName.QueueDuplicateDetection>): Promise<JobStatus> { async handleQueueSearchDuplicates({ force }: JobOf<JobName.AssetDetectDuplicatesQueueAll>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: false }); const { machineLearning } = await this.getConfig({ withCache: false });
if (!isDuplicateDetectionEnabled(machineLearning)) { if (!isDuplicateDetectionEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;
@ -44,7 +44,7 @@ export class DuplicateService extends BaseService {
const assets = this.assetJobRepository.streamForSearchDuplicates(force); const assets = this.assetJobRepository.streamForSearchDuplicates(force);
for await (const asset of assets) { for await (const asset of assets) {
jobs.push({ name: JobName.DuplicateDetection, data: { id: asset.id } }); jobs.push({ name: JobName.AssetDetectDuplicates, data: { id: asset.id } });
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
await queueAll(); await queueAll();
} }
@ -55,8 +55,8 @@ export class DuplicateService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.DuplicateDetection, queue: QueueName.DuplicateDetection }) @OnJob({ name: JobName.AssetDetectDuplicates, queue: QueueName.DuplicateDetection })
async handleSearchDuplicates({ id }: JobOf<JobName.DuplicateDetection>): Promise<JobStatus> { async handleSearchDuplicates({ id }: JobOf<JobName.AssetDetectDuplicates>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: true }); const { machineLearning } = await this.getConfig({ withCache: true });
if (!isDuplicateDetectionEnabled(machineLearning)) { if (!isDuplicateDetectionEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;

View File

@ -37,16 +37,16 @@ describe(JobService.name, () => {
await sut.handleNightlyJobs(); await sut.handleNightlyJobs();
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.AssetDeletionCheck }, { name: JobName.AssetDeleteCheck },
{ name: JobName.UserDeleteCheck }, { name: JobName.UserDeleteCheck },
{ name: JobName.PersonCleanup }, { name: JobName.PersonCleanup },
{ name: JobName.MemoriesCleanup }, { name: JobName.MemoryCleanup },
{ name: JobName.CleanOldSessionTokens }, { name: JobName.SessionCleanup },
{ name: JobName.CleanOldAuditLogs }, { name: JobName.AuditLogCleanup },
{ name: JobName.MemoriesCreate }, { name: JobName.MemoryGenerate },
{ name: JobName.userSyncUsage }, { name: JobName.UserSyncUsage },
{ name: JobName.QueueGenerateThumbnails, data: { force: false } }, { name: JobName.AssetGenerateThumbnailsQueueAll, data: { force: false } },
{ name: JobName.QueueFacialRecognition, data: { force: false, nightly: true } }, { name: JobName.FacialRecognitionQueueAll, data: { force: false, nightly: true } },
]); ]);
}); });
}); });
@ -136,7 +136,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.VideoConversion, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.VideoConversion, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueVideoConversion, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetEncodeVideoQueueAll, data: { force: false } });
}); });
it('should handle a start storage template migration command', async () => { it('should handle a start storage template migration command', async () => {
@ -152,7 +152,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.SmartSearch, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.SmartSearch, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueSmartSearch, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.SmartSearchQueueAll, data: { force: false } });
}); });
it('should handle a start metadata extraction command', async () => { it('should handle a start metadata extraction command', async () => {
@ -160,7 +160,10 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.MetadataExtraction, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.MetadataExtraction, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueMetadataExtraction, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.AssetExtractMetadataQueueAll,
data: { force: false },
});
}); });
it('should handle a start sidecar command', async () => { it('should handle a start sidecar command', async () => {
@ -168,7 +171,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.Sidecar, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.Sidecar, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueSidecar, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.SidecarQueueAll, data: { force: false } });
}); });
it('should handle a start thumbnail generation command', async () => { it('should handle a start thumbnail generation command', async () => {
@ -176,7 +179,10 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.ThumbnailGeneration, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.ThumbnailGeneration, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueGenerateThumbnails, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.AssetGenerateThumbnailsQueueAll,
data: { force: false },
});
}); });
it('should handle a start face detection command', async () => { it('should handle a start face detection command', async () => {
@ -184,7 +190,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.FaceDetection, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.FaceDetection, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueFaceDetection, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetDetectFacesQueueAll, data: { force: false } });
}); });
it('should handle a start facial recognition command', async () => { it('should handle a start facial recognition command', async () => {
@ -192,7 +198,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.FacialRecognition, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.FacialRecognition, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueFacialRecognition, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.FacialRecognitionQueueAll, data: { force: false } });
}); });
it('should handle a start backup database command', async () => { it('should handle a start backup database command', async () => {
@ -200,7 +206,7 @@ describe(JobService.name, () => {
await sut.handleCommand(QueueName.BackupDatabase, { command: JobCommand.Start, force: false }); await sut.handleCommand(QueueName.BackupDatabase, { command: JobCommand.Start, force: false });
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.BackupDatabase, data: { force: false } }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.DatabaseBackup, data: { force: false } });
}); });
it('should throw a bad request when an invalid queue is used', async () => { it('should throw a bad request when an invalid queue is used', async () => {
@ -220,55 +226,55 @@ describe(JobService.name, () => {
mocks.job.run.mockResolvedValue(JobStatus.Success); mocks.job.run.mockResolvedValue(JobStatus.Success);
await sut.onJobStart(QueueName.BackgroundTask, { await sut.onJobStart(QueueName.BackgroundTask, {
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: ['path/to/file'] }, data: { files: ['path/to/file'] },
}); });
expect(mocks.telemetry.jobs.addToGauge).toHaveBeenCalledWith('immich.queues.background_task.active', 1); expect(mocks.telemetry.jobs.addToGauge).toHaveBeenCalledWith('immich.queues.background_task.active', 1);
expect(mocks.telemetry.jobs.addToGauge).toHaveBeenCalledWith('immich.queues.background_task.active', -1); expect(mocks.telemetry.jobs.addToGauge).toHaveBeenCalledWith('immich.queues.background_task.active', -1);
expect(mocks.telemetry.jobs.addToCounter).toHaveBeenCalledWith('immich.jobs.delete_files.success', 1); expect(mocks.telemetry.jobs.addToCounter).toHaveBeenCalledWith('immich.jobs.file_delete.success', 1);
expect(mocks.logger.error).not.toHaveBeenCalled(); expect(mocks.logger.error).not.toHaveBeenCalled();
}); });
const tests: Array<{ item: JobItem; jobs: JobName[]; stub?: any }> = [ const tests: Array<{ item: JobItem; jobs: JobName[]; stub?: any }> = [
{ {
item: { name: JobName.SidecarSync, data: { id: 'asset-1' } }, item: { name: JobName.SidecarSync, data: { id: 'asset-1' } },
jobs: [JobName.MetadataExtraction], jobs: [JobName.AssetExtractMetadata],
}, },
{ {
item: { name: JobName.SidecarDiscovery, data: { id: 'asset-1' } }, item: { name: JobName.SidecarDiscovery, data: { id: 'asset-1' } },
jobs: [JobName.MetadataExtraction], jobs: [JobName.AssetExtractMetadata],
}, },
{ {
item: { name: JobName.StorageTemplateMigrationSingle, data: { id: 'asset-1', source: 'upload' } }, item: { name: JobName.StorageTemplateMigrationSingle, data: { id: 'asset-1', source: 'upload' } },
jobs: [JobName.GenerateThumbnails], jobs: [JobName.AssetGenerateThumbnails],
}, },
{ {
item: { name: JobName.StorageTemplateMigrationSingle, data: { id: 'asset-1' } }, item: { name: JobName.StorageTemplateMigrationSingle, data: { id: 'asset-1' } },
jobs: [], jobs: [],
}, },
{ {
item: { name: JobName.GeneratePersonThumbnail, data: { id: 'asset-1' } }, item: { name: JobName.PersonGenerateThumbnail, data: { id: 'asset-1' } },
jobs: [], jobs: [],
}, },
{ {
item: { name: JobName.GenerateThumbnails, data: { id: 'asset-1' } }, item: { name: JobName.AssetGenerateThumbnails, data: { id: 'asset-1' } },
jobs: [], jobs: [],
stub: [assetStub.image], stub: [assetStub.image],
}, },
{ {
item: { name: JobName.GenerateThumbnails, data: { id: 'asset-1' } }, item: { name: JobName.AssetGenerateThumbnails, data: { id: 'asset-1' } },
jobs: [], jobs: [],
stub: [assetStub.video], stub: [assetStub.video],
}, },
{ {
item: { name: JobName.GenerateThumbnails, data: { id: 'asset-1', source: 'upload' } }, item: { name: JobName.AssetGenerateThumbnails, data: { id: 'asset-1', source: 'upload' } },
jobs: [JobName.SmartSearch, JobName.FaceDetection], jobs: [JobName.SmartSearch, JobName.AssetDetectFaces],
stub: [assetStub.livePhotoStillAsset], stub: [assetStub.livePhotoStillAsset],
}, },
{ {
item: { name: JobName.GenerateThumbnails, data: { id: 'asset-1', source: 'upload' } }, item: { name: JobName.AssetGenerateThumbnails, data: { id: 'asset-1', source: 'upload' } },
jobs: [JobName.SmartSearch, JobName.FaceDetection, JobName.VideoConversation], jobs: [JobName.SmartSearch, JobName.AssetDetectFaces, JobName.AssetEncodeVideo],
stub: [assetStub.video], stub: [assetStub.video],
}, },
{ {
@ -276,7 +282,7 @@ describe(JobService.name, () => {
jobs: [], jobs: [],
}, },
{ {
item: { name: JobName.FaceDetection, data: { id: 'asset-1' } }, item: { name: JobName.AssetDetectFaces, data: { id: 'asset-1' } },
jobs: [], jobs: [],
}, },
{ {

View File

@ -40,15 +40,15 @@ const asJobItem = (dto: JobCreateDto): JobItem => {
} }
case ManualJobName.MemoryCleanup: { case ManualJobName.MemoryCleanup: {
return { name: JobName.MemoriesCleanup }; return { name: JobName.MemoryCleanup };
} }
case ManualJobName.MemoryCreate: { case ManualJobName.MemoryCreate: {
return { name: JobName.MemoriesCreate }; return { name: JobName.MemoryGenerate };
} }
case ManualJobName.BackupDatabase: { case ManualJobName.BackupDatabase: {
return { name: JobName.BackupDatabase }; return { name: JobName.DatabaseBackup };
} }
default: { default: {
@ -190,7 +190,7 @@ export class JobService extends BaseService {
switch (name) { switch (name) {
case QueueName.VideoConversion: { case QueueName.VideoConversion: {
return this.jobRepository.queue({ name: JobName.QueueVideoConversion, data: { force } }); return this.jobRepository.queue({ name: JobName.AssetEncodeVideoQueueAll, data: { force } });
} }
case QueueName.StorageTemplateMigration: { case QueueName.StorageTemplateMigration: {
@ -198,43 +198,43 @@ export class JobService extends BaseService {
} }
case QueueName.Migration: { case QueueName.Migration: {
return this.jobRepository.queue({ name: JobName.QueueMigration }); return this.jobRepository.queue({ name: JobName.FileMigrationQueueAll });
} }
case QueueName.SmartSearch: { case QueueName.SmartSearch: {
return this.jobRepository.queue({ name: JobName.QueueSmartSearch, data: { force } }); return this.jobRepository.queue({ name: JobName.SmartSearchQueueAll, data: { force } });
} }
case QueueName.DuplicateDetection: { case QueueName.DuplicateDetection: {
return this.jobRepository.queue({ name: JobName.QueueDuplicateDetection, data: { force } }); return this.jobRepository.queue({ name: JobName.AssetDetectDuplicatesQueueAll, data: { force } });
} }
case QueueName.MetadataExtraction: { case QueueName.MetadataExtraction: {
return this.jobRepository.queue({ name: JobName.QueueMetadataExtraction, data: { force } }); return this.jobRepository.queue({ name: JobName.AssetExtractMetadataQueueAll, data: { force } });
} }
case QueueName.Sidecar: { case QueueName.Sidecar: {
return this.jobRepository.queue({ name: JobName.QueueSidecar, data: { force } }); return this.jobRepository.queue({ name: JobName.SidecarQueueAll, data: { force } });
} }
case QueueName.ThumbnailGeneration: { case QueueName.ThumbnailGeneration: {
return this.jobRepository.queue({ name: JobName.QueueGenerateThumbnails, data: { force } }); return this.jobRepository.queue({ name: JobName.AssetGenerateThumbnailsQueueAll, data: { force } });
} }
case QueueName.FaceDetection: { case QueueName.FaceDetection: {
return this.jobRepository.queue({ name: JobName.QueueFaceDetection, data: { force } }); return this.jobRepository.queue({ name: JobName.AssetDetectFacesQueueAll, data: { force } });
} }
case QueueName.FacialRecognition: { case QueueName.FacialRecognition: {
return this.jobRepository.queue({ name: JobName.QueueFacialRecognition, data: { force } }); return this.jobRepository.queue({ name: JobName.FacialRecognitionQueueAll, data: { force } });
} }
case QueueName.Library: { case QueueName.Library: {
return this.jobRepository.queue({ name: JobName.LibraryQueueScanAll, data: { force } }); return this.jobRepository.queue({ name: JobName.LibraryScanQueueAll, data: { force } });
} }
case QueueName.BackupDatabase: { case QueueName.BackupDatabase: {
return this.jobRepository.queue({ name: JobName.BackupDatabase, data: { force } }); return this.jobRepository.queue({ name: JobName.DatabaseBackup, data: { force } });
} }
default: { default: {
@ -249,7 +249,7 @@ export class JobService extends BaseService {
this.telemetryRepository.jobs.addToGauge(queueMetric, 1); this.telemetryRepository.jobs.addToGauge(queueMetric, 1);
try { try {
const status = await this.jobRepository.run(job); const status = await this.jobRepository.run(job);
const jobMetric = `immich.jobs.${job.name.replaceAll('-', '_')}.${status}`; const jobMetric = `immich.jobs.${snakeCase(job.name)}.${status}`;
this.telemetryRepository.jobs.addToCounter(jobMetric, 1); this.telemetryRepository.jobs.addToCounter(jobMetric, 1);
if (status === JobStatus.Success || status == JobStatus.Skipped) { if (status === JobStatus.Success || status == JobStatus.Skipped) {
await this.onDone(job); await this.onDone(job);
@ -276,29 +276,29 @@ export class JobService extends BaseService {
if (config.nightlyTasks.databaseCleanup) { if (config.nightlyTasks.databaseCleanup) {
jobs.push( jobs.push(
{ name: JobName.AssetDeletionCheck }, { name: JobName.AssetDeleteCheck },
{ name: JobName.UserDeleteCheck }, { name: JobName.UserDeleteCheck },
{ name: JobName.PersonCleanup }, { name: JobName.PersonCleanup },
{ name: JobName.MemoriesCleanup }, { name: JobName.MemoryCleanup },
{ name: JobName.CleanOldSessionTokens }, { name: JobName.SessionCleanup },
{ name: JobName.CleanOldAuditLogs }, { name: JobName.AuditLogCleanup },
); );
} }
if (config.nightlyTasks.generateMemories) { if (config.nightlyTasks.generateMemories) {
jobs.push({ name: JobName.MemoriesCreate }); jobs.push({ name: JobName.MemoryGenerate });
} }
if (config.nightlyTasks.syncQuotaUsage) { if (config.nightlyTasks.syncQuotaUsage) {
jobs.push({ name: JobName.userSyncUsage }); jobs.push({ name: JobName.UserSyncUsage });
} }
if (config.nightlyTasks.missingThumbnails) { if (config.nightlyTasks.missingThumbnails) {
jobs.push({ name: JobName.QueueGenerateThumbnails, data: { force: false } }); jobs.push({ name: JobName.AssetGenerateThumbnailsQueueAll, data: { force: false } });
} }
if (config.nightlyTasks.clusterNewFaces) { if (config.nightlyTasks.clusterNewFaces) {
jobs.push({ name: JobName.QueueFacialRecognition, data: { force: false, nightly: true } }); jobs.push({ name: JobName.FacialRecognitionQueueAll, data: { force: false, nightly: true } });
} }
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
@ -311,13 +311,13 @@ export class JobService extends BaseService {
switch (item.name) { switch (item.name) {
case JobName.SidecarSync: case JobName.SidecarSync:
case JobName.SidecarDiscovery: { case JobName.SidecarDiscovery: {
await this.jobRepository.queue({ name: JobName.MetadataExtraction, data: item.data }); await this.jobRepository.queue({ name: JobName.AssetExtractMetadata, data: item.data });
break; break;
} }
case JobName.SidecarWrite: { case JobName.SidecarWrite: {
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.MetadataExtraction, name: JobName.AssetExtractMetadata,
data: { id: item.data.id, source: 'sidecar-write' }, data: { id: item.data.id, source: 'sidecar-write' },
}); });
break; break;
@ -325,12 +325,12 @@ export class JobService extends BaseService {
case JobName.StorageTemplateMigrationSingle: { case JobName.StorageTemplateMigrationSingle: {
if (item.data.source === 'upload' || item.data.source === 'copy') { if (item.data.source === 'upload' || item.data.source === 'copy') {
await this.jobRepository.queue({ name: JobName.GenerateThumbnails, data: item.data }); await this.jobRepository.queue({ name: JobName.AssetGenerateThumbnails, data: item.data });
} }
break; break;
} }
case JobName.GeneratePersonThumbnail: { case JobName.PersonGenerateThumbnail: {
const { id } = item.data; const { id } = item.data;
const person = await this.personRepository.getById(id); const person = await this.personRepository.getById(id);
if (person) { if (person) {
@ -339,7 +339,7 @@ export class JobService extends BaseService {
break; break;
} }
case JobName.GenerateThumbnails: { case JobName.AssetGenerateThumbnails: {
if (!item.data.notify && item.data.source !== 'upload') { if (!item.data.notify && item.data.source !== 'upload') {
break; break;
} }
@ -352,11 +352,11 @@ export class JobService extends BaseService {
const jobs: JobItem[] = [ const jobs: JobItem[] = [
{ name: JobName.SmartSearch, data: item.data }, { name: JobName.SmartSearch, data: item.data },
{ name: JobName.FaceDetection, data: item.data }, { name: JobName.AssetDetectFaces, data: item.data },
]; ];
if (asset.type === AssetType.Video) { if (asset.type === AssetType.Video) {
jobs.push({ name: JobName.VideoConversation, data: item.data }); jobs.push({ name: JobName.AssetEncodeVideo, data: item.data });
} }
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
@ -419,12 +419,12 @@ export class JobService extends BaseService {
case JobName.SmartSearch: { case JobName.SmartSearch: {
if (item.data.source === 'upload') { if (item.data.source === 'upload') {
await this.jobRepository.queue({ name: JobName.DuplicateDetection, data: item.data }); await this.jobRepository.queue({ name: JobName.AssetDetectDuplicates, data: item.data });
} }
break; break;
} }
case JobName.UserDeletion: { case JobName.UserDelete: {
this.eventRepository.clientBroadcast('on_user_delete', item.data.id); this.eventRepository.clientBroadcast('on_user_delete', item.data.id);
break; break;
} }

View File

@ -1010,7 +1010,7 @@ describe(LibraryService.name, () => {
await sut.watchAll(); await sut.watchAll();
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.LibraryAssetRemoval, name: JobName.LibraryRemoveAsset,
data: { data: {
libraryId: library.id, libraryId: library.id,
paths: [assetStub.image.originalPath], paths: [assetStub.image.originalPath],
@ -1131,11 +1131,11 @@ describe(LibraryService.name, () => {
expect(mocks.job.queue).toHaveBeenCalledTimes(2); expect(mocks.job.queue).toHaveBeenCalledTimes(2);
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.LibraryQueueSyncFiles, name: JobName.LibrarySyncFilesQueueAll,
data: { id: library.id }, data: { id: library.id },
}); });
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.LibraryQueueSyncAssets, name: JobName.LibrarySyncAssetsQueueAll,
data: { id: library.id }, data: { id: library.id },
}); });
}); });
@ -1150,11 +1150,11 @@ describe(LibraryService.name, () => {
await expect(sut.handleQueueScanAll()).resolves.toBe(JobStatus.Success); await expect(sut.handleQueueScanAll()).resolves.toBe(JobStatus.Success);
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.LibraryQueueCleanup, name: JobName.LibraryDeleteCheck,
data: {}, data: {},
}); });
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.LibraryQueueSyncFiles, data: { id: library.id } }, { name: JobName.LibrarySyncFilesQueueAll, data: { id: library.id } },
]); ]);
}); });
}); });

View File

@ -47,7 +47,7 @@ export class LibraryService extends BaseService {
this.cronRepository.create({ this.cronRepository.create({
name: CronJob.LibraryScan, name: CronJob.LibraryScan,
expression: scan.cronExpression, expression: scan.cronExpression,
onTick: () => handlePromiseError(this.jobRepository.queue({ name: JobName.LibraryQueueScanAll }), this.logger), onTick: () => handlePromiseError(this.jobRepository.queue({ name: JobName.LibraryScanQueueAll }), this.logger),
start: scan.enabled, start: scan.enabled,
}); });
} }
@ -113,7 +113,7 @@ export class LibraryService extends BaseService {
const deletionHandler = async (path: string) => { const deletionHandler = async (path: string) => {
this.logger.debug(`File unlink event received for ${path} in library ${library.id}}`); this.logger.debug(`File unlink event received for ${path} in library ${library.id}}`);
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.LibraryAssetRemoval, name: JobName.LibraryRemoveAsset,
data: { libraryId: library.id, paths: [path] }, data: { libraryId: library.id, paths: [path] },
}); });
}; };
@ -198,7 +198,7 @@ export class LibraryService extends BaseService {
return libraries.map((library) => mapLibrary(library)); return libraries.map((library) => mapLibrary(library));
} }
@OnJob({ name: JobName.LibraryQueueCleanup, queue: QueueName.Library }) @OnJob({ name: JobName.LibraryDeleteCheck, queue: QueueName.Library })
async handleQueueCleanup(): Promise<JobStatus> { async handleQueueCleanup(): Promise<JobStatus> {
this.logger.log('Checking for any libraries pending deletion...'); this.logger.log('Checking for any libraries pending deletion...');
const pendingDeletions = await this.libraryRepository.getAllDeleted(); const pendingDeletions = await this.libraryRepository.getAllDeleted();
@ -355,7 +355,7 @@ export class LibraryService extends BaseService {
assetsFound = true; assetsFound = true;
this.logger.debug(`Queueing deletion of ${chunk.length} asset(s) in library ${libraryId}`); this.logger.debug(`Queueing deletion of ${chunk.length} asset(s) in library ${libraryId}`);
await this.jobRepository.queueAll( await this.jobRepository.queueAll(
chunk.map((id) => ({ name: JobName.AssetDeletion, data: { id, deleteOnDisk: false } })), chunk.map((id) => ({ name: JobName.AssetDelete, data: { id, deleteOnDisk: false } })),
); );
chunk = []; chunk = [];
} }
@ -422,30 +422,30 @@ export class LibraryService extends BaseService {
this.logger.log(`Starting to scan library ${id}`); this.logger.log(`Starting to scan library ${id}`);
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.LibraryQueueSyncFiles, name: JobName.LibrarySyncFilesQueueAll,
data: { data: {
id, id,
}, },
}); });
await this.jobRepository.queue({ name: JobName.LibraryQueueSyncAssets, data: { id } }); await this.jobRepository.queue({ name: JobName.LibrarySyncAssetsQueueAll, data: { id } });
} }
async queueScanAll() { async queueScanAll() {
await this.jobRepository.queue({ name: JobName.LibraryQueueScanAll, data: {} }); await this.jobRepository.queue({ name: JobName.LibraryScanQueueAll, data: {} });
} }
@OnJob({ name: JobName.LibraryQueueScanAll, queue: QueueName.Library }) @OnJob({ name: JobName.LibraryScanQueueAll, queue: QueueName.Library })
async handleQueueScanAll(): Promise<JobStatus> { async handleQueueScanAll(): Promise<JobStatus> {
this.logger.log(`Initiating scan of all external libraries...`); this.logger.log(`Initiating scan of all external libraries...`);
await this.jobRepository.queue({ name: JobName.LibraryQueueCleanup, data: {} }); await this.jobRepository.queue({ name: JobName.LibraryDeleteCheck, data: {} });
const libraries = await this.libraryRepository.getAll(true); const libraries = await this.libraryRepository.getAll(true);
await this.jobRepository.queueAll( await this.jobRepository.queueAll(
libraries.map((library) => ({ libraries.map((library) => ({
name: JobName.LibraryQueueSyncFiles, name: JobName.LibrarySyncFilesQueueAll,
data: { data: {
id: library.id, id: library.id,
}, },
@ -453,7 +453,7 @@ export class LibraryService extends BaseService {
); );
await this.jobRepository.queueAll( await this.jobRepository.queueAll(
libraries.map((library) => ({ libraries.map((library) => ({
name: JobName.LibraryQueueSyncAssets, name: JobName.LibrarySyncAssetsQueueAll,
data: { data: {
id: library.id, id: library.id,
}, },
@ -598,8 +598,8 @@ export class LibraryService extends BaseService {
return AssetSyncResult.DO_NOTHING; return AssetSyncResult.DO_NOTHING;
} }
@OnJob({ name: JobName.LibraryQueueSyncFiles, queue: QueueName.Library }) @OnJob({ name: JobName.LibrarySyncFilesQueueAll, queue: QueueName.Library })
async handleQueueSyncFiles(job: JobOf<JobName.LibraryQueueSyncFiles>): Promise<JobStatus> { async handleQueueSyncFiles(job: JobOf<JobName.LibrarySyncFilesQueueAll>): Promise<JobStatus> {
const library = await this.libraryRepository.get(job.id); const library = await this.libraryRepository.get(job.id);
if (!library) { if (!library) {
this.logger.debug(`Library ${job.id} not found, skipping refresh`); this.logger.debug(`Library ${job.id} not found, skipping refresh`);
@ -668,8 +668,8 @@ export class LibraryService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.LibraryAssetRemoval, queue: QueueName.Library }) @OnJob({ name: JobName.LibraryRemoveAsset, queue: QueueName.Library })
async handleAssetRemoval(job: JobOf<JobName.LibraryAssetRemoval>): Promise<JobStatus> { async handleAssetRemoval(job: JobOf<JobName.LibraryRemoveAsset>): Promise<JobStatus> {
// This is only for handling file unlink events via the file watcher // This is only for handling file unlink events via the file watcher
this.logger.verbose(`Deleting asset(s) ${job.paths} from library ${job.libraryId}`); this.logger.verbose(`Deleting asset(s) ${job.paths} from library ${job.libraryId}`);
for (const assetPath of job.paths) { for (const assetPath of job.paths) {
@ -682,8 +682,8 @@ export class LibraryService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.LibraryQueueSyncAssets, queue: QueueName.Library }) @OnJob({ name: JobName.LibrarySyncAssetsQueueAll, queue: QueueName.Library })
async handleQueueSyncAssets(job: JobOf<JobName.LibraryQueueSyncAssets>): Promise<JobStatus> { async handleQueueSyncAssets(job: JobOf<JobName.LibrarySyncAssetsQueueAll>): Promise<JobStatus> {
const library = await this.libraryRepository.get(job.id); const library = await this.libraryRepository.get(job.id);
if (!library) { if (!library) {
return JobStatus.Skipped; return JobStatus.Skipped;

View File

@ -49,7 +49,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -57,7 +57,7 @@ describe(MediaService.name, () => {
expect(mocks.person.getAll).toHaveBeenCalledWith(undefined); expect(mocks.person.getAll).toHaveBeenCalledWith(undefined);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: personStub.newThumbnail.id }, data: { id: personStub.newThumbnail.id },
}, },
]); ]);
@ -72,7 +72,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.trashed.id }, data: { id: assetStub.trashed.id },
}, },
]); ]);
@ -87,7 +87,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.archived.id }, data: { id: assetStub.archived.id },
}, },
]); ]);
@ -106,7 +106,7 @@ describe(MediaService.name, () => {
expect(mocks.person.update).toHaveBeenCalledTimes(1); expect(mocks.person.update).toHaveBeenCalledTimes(1);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { data: {
id: personStub.newThumbnail.id, id: personStub.newThumbnail.id,
}, },
@ -122,7 +122,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -138,7 +138,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -154,7 +154,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith(false);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -173,10 +173,10 @@ describe(MediaService.name, () => {
expect(mocks.storage.removeEmptyDirs).toHaveBeenCalledTimes(2); expect(mocks.storage.removeEmptyDirs).toHaveBeenCalledTimes(2);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.MigrateAsset, data: { id: assetStub.image.id } }, { name: JobName.AssetFileMigration, data: { id: assetStub.image.id } },
]); ]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.MigratePerson, data: { id: personStub.withName.id } }, { name: JobName.PersonFileMigration, data: { id: personStub.withName.id } },
]); ]);
}); });
}); });
@ -1243,7 +1243,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForVideoConversion).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForVideoConversion).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.VideoConversation, name: JobName.AssetEncodeVideo,
data: { id: assetStub.video.id }, data: { id: assetStub.video.id },
}, },
]); ]);
@ -1257,7 +1257,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForVideoConversion).toHaveBeenCalledWith(void 0); expect(mocks.assetJob.streamForVideoConversion).toHaveBeenCalledWith(void 0);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.VideoConversation, name: JobName.AssetEncodeVideo,
data: { id: assetStub.video.id }, data: { id: assetStub.video.id },
}, },
]); ]);
@ -1616,7 +1616,7 @@ describe(MediaService.name, () => {
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.DeleteFiles, name: JobName.FileDelete,
data: { files: [asset.encodedVideoPath] }, data: { files: [asset.encodedVideoPath] },
}); });
}); });

View File

@ -57,8 +57,8 @@ export class MediaService extends BaseService {
this.videoInterfaces = { dri, mali }; this.videoInterfaces = { dri, mali };
} }
@OnJob({ name: JobName.QueueGenerateThumbnails, queue: QueueName.ThumbnailGeneration }) @OnJob({ name: JobName.AssetGenerateThumbnailsQueueAll, queue: QueueName.ThumbnailGeneration })
async handleQueueGenerateThumbnails({ force }: JobOf<JobName.QueueGenerateThumbnails>): Promise<JobStatus> { async handleQueueGenerateThumbnails({ force }: JobOf<JobName.AssetGenerateThumbnailsQueueAll>): Promise<JobStatus> {
let jobs: JobItem[] = []; let jobs: JobItem[] = [];
const queueAll = async () => { const queueAll = async () => {
@ -70,7 +70,7 @@ export class MediaService extends BaseService {
const { previewFile, thumbnailFile } = getAssetFiles(asset.files); const { previewFile, thumbnailFile } = getAssetFiles(asset.files);
if (!previewFile || !thumbnailFile || !asset.thumbhash || force) { if (!previewFile || !thumbnailFile || !asset.thumbhash || force) {
jobs.push({ name: JobName.GenerateThumbnails, data: { id: asset.id } }); jobs.push({ name: JobName.AssetGenerateThumbnails, data: { id: asset.id } });
} }
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
@ -92,7 +92,7 @@ export class MediaService extends BaseService {
await this.personRepository.update({ id: person.id, faceAssetId: face.id }); await this.personRepository.update({ id: person.id, faceAssetId: face.id });
} }
jobs.push({ name: JobName.GeneratePersonThumbnail, data: { id: person.id } }); jobs.push({ name: JobName.PersonGenerateThumbnail, data: { id: person.id } });
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
await queueAll(); await queueAll();
} }
@ -103,7 +103,7 @@ export class MediaService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.QueueMigration, queue: QueueName.Migration }) @OnJob({ name: JobName.FileMigrationQueueAll, queue: QueueName.Migration })
async handleQueueMigration(): Promise<JobStatus> { async handleQueueMigration(): Promise<JobStatus> {
const { active, waiting } = await this.jobRepository.getJobCounts(QueueName.Migration); const { active, waiting } = await this.jobRepository.getJobCounts(QueueName.Migration);
if (active === 1 && waiting === 0) { if (active === 1 && waiting === 0) {
@ -114,7 +114,7 @@ export class MediaService extends BaseService {
let jobs: JobItem[] = []; let jobs: JobItem[] = [];
const assets = this.assetJobRepository.streamForMigrationJob(); const assets = this.assetJobRepository.streamForMigrationJob();
for await (const asset of assets) { for await (const asset of assets) {
jobs.push({ name: JobName.MigrateAsset, data: { id: asset.id } }); jobs.push({ name: JobName.AssetFileMigration, data: { id: asset.id } });
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
jobs = []; jobs = [];
@ -125,7 +125,7 @@ export class MediaService extends BaseService {
jobs = []; jobs = [];
for await (const person of this.personRepository.getAll()) { for await (const person of this.personRepository.getAll()) {
jobs.push({ name: JobName.MigratePerson, data: { id: person.id } }); jobs.push({ name: JobName.PersonFileMigration, data: { id: person.id } });
if (jobs.length === JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length === JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
@ -138,8 +138,8 @@ export class MediaService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.MigrateAsset, queue: QueueName.Migration }) @OnJob({ name: JobName.AssetFileMigration, queue: QueueName.Migration })
async handleAssetMigration({ id }: JobOf<JobName.MigrateAsset>): Promise<JobStatus> { async handleAssetMigration({ id }: JobOf<JobName.AssetFileMigration>): Promise<JobStatus> {
const { image } = await this.getConfig({ withCache: true }); const { image } = await this.getConfig({ withCache: true });
const asset = await this.assetJobRepository.getForMigrationJob(id); const asset = await this.assetJobRepository.getForMigrationJob(id);
if (!asset) { if (!asset) {
@ -154,8 +154,8 @@ export class MediaService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.GenerateThumbnails, queue: QueueName.ThumbnailGeneration }) @OnJob({ name: JobName.AssetGenerateThumbnails, queue: QueueName.ThumbnailGeneration })
async handleGenerateThumbnails({ id }: JobOf<JobName.GenerateThumbnails>): Promise<JobStatus> { async handleGenerateThumbnails({ id }: JobOf<JobName.AssetGenerateThumbnails>): Promise<JobStatus> {
const asset = await this.assetJobRepository.getForGenerateThumbnailJob(id); const asset = await this.assetJobRepository.getForGenerateThumbnailJob(id);
if (!asset) { if (!asset) {
this.logger.warn(`Thumbnail generation failed for asset ${id}: not found`); this.logger.warn(`Thumbnail generation failed for asset ${id}: not found`);
@ -317,8 +317,8 @@ export class MediaService extends BaseService {
return { previewPath, thumbnailPath, fullsizePath, thumbhash: outputs[0] as Buffer }; return { previewPath, thumbnailPath, fullsizePath, thumbhash: outputs[0] as Buffer };
} }
@OnJob({ name: JobName.GeneratePersonThumbnail, queue: QueueName.ThumbnailGeneration }) @OnJob({ name: JobName.PersonGenerateThumbnail, queue: QueueName.ThumbnailGeneration })
async handleGeneratePersonThumbnail({ id }: JobOf<JobName.GeneratePersonThumbnail>): Promise<JobStatus> { async handleGeneratePersonThumbnail({ id }: JobOf<JobName.PersonGenerateThumbnail>): Promise<JobStatus> {
const { machineLearning, metadata, image } = await this.getConfig({ withCache: true }); const { machineLearning, metadata, image } = await this.getConfig({ withCache: true });
if (!isFacialRecognitionEnabled(machineLearning) && !isFaceImportEnabled(metadata)) { if (!isFacialRecognitionEnabled(machineLearning) && !isFaceImportEnabled(metadata)) {
return JobStatus.Skipped; return JobStatus.Skipped;
@ -443,13 +443,13 @@ export class MediaService extends BaseService {
return { previewPath, thumbnailPath, thumbhash }; return { previewPath, thumbnailPath, thumbhash };
} }
@OnJob({ name: JobName.QueueVideoConversion, queue: QueueName.VideoConversion }) @OnJob({ name: JobName.AssetEncodeVideoQueueAll, queue: QueueName.VideoConversion })
async handleQueueVideoConversion(job: JobOf<JobName.QueueVideoConversion>): Promise<JobStatus> { async handleQueueVideoConversion(job: JobOf<JobName.AssetEncodeVideoQueueAll>): Promise<JobStatus> {
const { force } = job; const { force } = job;
let queue: { name: JobName.VideoConversation; data: { id: string } }[] = []; let queue: { name: JobName.AssetEncodeVideo; data: { id: string } }[] = [];
for await (const asset of this.assetJobRepository.streamForVideoConversion(force)) { for await (const asset of this.assetJobRepository.streamForVideoConversion(force)) {
queue.push({ name: JobName.VideoConversation, data: { id: asset.id } }); queue.push({ name: JobName.AssetEncodeVideo, data: { id: asset.id } });
if (queue.length >= JOBS_ASSET_PAGINATION_SIZE) { if (queue.length >= JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(queue); await this.jobRepository.queueAll(queue);
@ -462,8 +462,8 @@ export class MediaService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.VideoConversation, queue: QueueName.VideoConversion }) @OnJob({ name: JobName.AssetEncodeVideo, queue: QueueName.VideoConversion })
async handleVideoConversion({ id }: JobOf<JobName.VideoConversation>): Promise<JobStatus> { async handleVideoConversion({ id }: JobOf<JobName.AssetEncodeVideo>): Promise<JobStatus> {
const asset = await this.assetJobRepository.getForVideoConversion(id); const asset = await this.assetJobRepository.getForVideoConversion(id);
if (!asset) { if (!asset) {
return JobStatus.Failed; return JobStatus.Failed;
@ -492,7 +492,7 @@ export class MediaService extends BaseService {
if (target === TranscodeTarget.None && !this.isRemuxRequired(ffmpeg, format)) { if (target === TranscodeTarget.None && !this.isRemuxRequired(ffmpeg, format)) {
if (asset.encodedVideoPath) { if (asset.encodedVideoPath) {
this.logger.log(`Transcoded video exists for asset ${asset.id}, but is no longer required. Deleting...`); this.logger.log(`Transcoded video exists for asset ${asset.id}, but is no longer required. Deleting...`);
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files: [asset.encodedVideoPath] } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [asset.encodedVideoPath] } });
await this.assetRepository.update({ id: asset.id, encodedVideoPath: null }); await this.assetRepository.update({ id: asset.id, encodedVideoPath: null });
} else { } else {
this.logger.verbose(`Asset ${asset.id} does not require transcoding based on current policy, skipping`); this.logger.verbose(`Asset ${asset.id} does not require transcoding based on current policy, skipping`);

View File

@ -12,7 +12,7 @@ const DAYS = 3;
@Injectable() @Injectable()
export class MemoryService extends BaseService { export class MemoryService extends BaseService {
@OnJob({ name: JobName.MemoriesCreate, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.MemoryGenerate, queue: QueueName.BackgroundTask })
async onMemoriesCreate() { async onMemoriesCreate() {
const users = await this.userRepository.getList({ withDeleted: false }); const users = await this.userRepository.getList({ withDeleted: false });
const usersIds = await Promise.all( const usersIds = await Promise.all(
@ -72,7 +72,7 @@ export class MemoryService extends BaseService {
); );
} }
@OnJob({ name: JobName.MemoriesCleanup, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.MemoryCleanup, queue: QueueName.BackgroundTask })
async onMemoriesCleanup() { async onMemoriesCleanup() {
await this.memoryRepository.cleanup(); await this.memoryRepository.cleanup();
} }

View File

@ -106,7 +106,7 @@ describe(MetadataService.name, () => {
expect(mocks.assetJob.streamForMetadataExtraction).toHaveBeenCalledWith(false); expect(mocks.assetJob.streamForMetadataExtraction).toHaveBeenCalledWith(false);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.MetadataExtraction, name: JobName.AssetExtractMetadata,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -119,7 +119,7 @@ describe(MetadataService.name, () => {
expect(mocks.assetJob.streamForMetadataExtraction).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForMetadataExtraction).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.MetadataExtraction, name: JobName.AssetExtractMetadata,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -599,7 +599,7 @@ describe(MetadataService.name, () => {
}); });
expect(mocks.asset.update).toHaveBeenCalledTimes(3); expect(mocks.asset.update).toHaveBeenCalledTimes(3);
expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({ expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({
name: JobName.VideoConversation, name: JobName.AssetEncodeVideo,
data: { id: assetStub.livePhotoMotionAsset.id }, data: { id: assetStub.livePhotoMotionAsset.id },
}); });
}); });
@ -657,7 +657,7 @@ describe(MetadataService.name, () => {
}); });
expect(mocks.asset.update).toHaveBeenCalledTimes(3); expect(mocks.asset.update).toHaveBeenCalledTimes(3);
expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({ expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({
name: JobName.VideoConversation, name: JobName.AssetEncodeVideo,
data: { id: assetStub.livePhotoMotionAsset.id }, data: { id: assetStub.livePhotoMotionAsset.id },
}); });
}); });
@ -715,7 +715,7 @@ describe(MetadataService.name, () => {
}); });
expect(mocks.asset.update).toHaveBeenCalledTimes(3); expect(mocks.asset.update).toHaveBeenCalledTimes(3);
expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({ expect(mocks.job.queue).toHaveBeenCalledExactlyOnceWith({
name: JobName.VideoConversation, name: JobName.AssetEncodeVideo,
data: { id: assetStub.livePhotoMotionAsset.id }, data: { id: assetStub.livePhotoMotionAsset.id },
}); });
}); });
@ -737,7 +737,7 @@ describe(MetadataService.name, () => {
await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id }); await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id });
expect(mocks.job.queue).toHaveBeenNthCalledWith(1, { expect(mocks.job.queue).toHaveBeenNthCalledWith(1, {
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { id: assetStub.livePhotoWithOriginalFileName.livePhotoVideoId, deleteOnDisk: true }, data: { id: assetStub.livePhotoWithOriginalFileName.livePhotoVideoId, deleteOnDisk: true },
}); });
}); });
@ -1116,7 +1116,7 @@ describe(MetadataService.name, () => {
]); ]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: personStub.withName.id }, data: { id: personStub.withName.id },
}, },
]); ]);
@ -1244,7 +1244,7 @@ describe(MetadataService.name, () => {
]); ]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: personStub.withName.id }, data: { id: personStub.withName.id },
}, },
]); ]);

View File

@ -193,13 +193,13 @@ export class MetadataService extends BaseService {
await this.eventRepository.emit('AssetHide', { assetId: motionAsset.id, userId: motionAsset.ownerId }); await this.eventRepository.emit('AssetHide', { assetId: motionAsset.id, userId: motionAsset.ownerId });
} }
@OnJob({ name: JobName.QueueMetadataExtraction, queue: QueueName.MetadataExtraction }) @OnJob({ name: JobName.AssetExtractMetadataQueueAll, queue: QueueName.MetadataExtraction })
async handleQueueMetadataExtraction(job: JobOf<JobName.QueueMetadataExtraction>): Promise<JobStatus> { async handleQueueMetadataExtraction(job: JobOf<JobName.AssetExtractMetadataQueueAll>): Promise<JobStatus> {
const { force } = job; const { force } = job;
let queue: { name: JobName.MetadataExtraction; data: { id: string } }[] = []; let queue: { name: JobName.AssetExtractMetadata; data: { id: string } }[] = [];
for await (const asset of this.assetJobRepository.streamForMetadataExtraction(force)) { for await (const asset of this.assetJobRepository.streamForMetadataExtraction(force)) {
queue.push({ name: JobName.MetadataExtraction, data: { id: asset.id } }); queue.push({ name: JobName.AssetExtractMetadata, data: { id: asset.id } });
if (queue.length >= JOBS_ASSET_PAGINATION_SIZE) { if (queue.length >= JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(queue); await this.jobRepository.queueAll(queue);
@ -211,8 +211,8 @@ export class MetadataService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.MetadataExtraction, queue: QueueName.MetadataExtraction }) @OnJob({ name: JobName.AssetExtractMetadata, queue: QueueName.MetadataExtraction })
async handleMetadataExtraction(data: JobOf<JobName.MetadataExtraction>) { async handleMetadataExtraction(data: JobOf<JobName.AssetExtractMetadata>) {
const [{ metadata, reverseGeocoding }, asset] = await Promise.all([ const [{ metadata, reverseGeocoding }, asset] = await Promise.all([
this.getConfig({ withCache: true }), this.getConfig({ withCache: true }),
this.assetJobRepository.getForMetadataExtraction(data.id), this.assetJobRepository.getForMetadataExtraction(data.id),
@ -320,8 +320,8 @@ export class MetadataService extends BaseService {
}); });
} }
@OnJob({ name: JobName.QueueSidecar, queue: QueueName.Sidecar }) @OnJob({ name: JobName.SidecarQueueAll, queue: QueueName.Sidecar })
async handleQueueSidecar({ force }: JobOf<JobName.QueueSidecar>): Promise<JobStatus> { async handleQueueSidecar({ force }: JobOf<JobName.SidecarQueueAll>): Promise<JobStatus> {
let jobs: JobItem[] = []; let jobs: JobItem[] = [];
const queueAll = async () => { const queueAll = async () => {
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
@ -597,7 +597,7 @@ export class MetadataService extends BaseService {
// note asset.livePhotoVideoId is not motionAsset.id yet // note asset.livePhotoVideoId is not motionAsset.id yet
if (asset.livePhotoVideoId) { if (asset.livePhotoVideoId) {
await this.jobRepository.queue({ await this.jobRepository.queue({
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { id: asset.livePhotoVideoId, deleteOnDisk: true }, data: { id: asset.livePhotoVideoId, deleteOnDisk: true },
}); });
this.logger.log(`Removed old motion photo video asset (${asset.livePhotoVideoId})`); this.logger.log(`Removed old motion photo video asset (${asset.livePhotoVideoId})`);
@ -612,7 +612,7 @@ export class MetadataService extends BaseService {
this.logger.log(`Wrote motion photo video to ${motionAsset.originalPath}`); this.logger.log(`Wrote motion photo video to ${motionAsset.originalPath}`);
await this.handleMetadataExtraction({ id: motionAsset.id }); await this.handleMetadataExtraction({ id: motionAsset.id });
await this.jobRepository.queue({ name: JobName.VideoConversation, data: { id: motionAsset.id } }); await this.jobRepository.queue({ name: JobName.AssetEncodeVideo, data: { id: motionAsset.id } });
} }
this.logger.debug(`Finished motion photo video extraction for asset ${asset.id}: ${asset.originalPath}`); this.logger.debug(`Finished motion photo video extraction for asset ${asset.id}: ${asset.originalPath}`);
@ -753,7 +753,7 @@ export class MetadataService extends BaseService {
if (missing.length > 0) { if (missing.length > 0) {
this.logger.debugFn(() => `Creating missing persons: ${missing.map((p) => `${p.name}/${p.id}`)}`); this.logger.debugFn(() => `Creating missing persons: ${missing.map((p) => `${p.name}/${p.id}`)}`);
const newPersonIds = await this.personRepository.createAll(missing); const newPersonIds = await this.personRepository.createAll(missing);
const jobs = newPersonIds.map((id) => ({ name: JobName.GeneratePersonThumbnail, data: { id } }) as const); const jobs = newPersonIds.map((id) => ({ name: JobName.PersonGenerateThumbnail, data: { id } }) as const);
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
} }

View File

@ -131,7 +131,7 @@ describe(NotificationService.name, () => {
it('should queue the generate thumbnail job', async () => { it('should queue the generate thumbnail job', async () => {
await sut.onAssetShow({ assetId: 'asset-id', userId: 'user-id' }); await sut.onAssetShow({ assetId: 'asset-id', userId: 'user-id' });
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.GenerateThumbnails, name: JobName.AssetGenerateThumbnails,
data: { id: 'asset-id', notify: true }, data: { id: 'asset-id', notify: true },
}); });
}); });
@ -146,7 +146,7 @@ describe(NotificationService.name, () => {
it('should queue notify signup event if notify is true', async () => { it('should queue notify signup event if notify is true', async () => {
await sut.onUserSignup({ id: '', notify: true }); await sut.onUserSignup({ id: '', notify: true });
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.NotifySignup, name: JobName.NotifyUserSignup,
data: { id: '', tempPassword: undefined }, data: { id: '', tempPassword: undefined },
}); });
}); });

View File

@ -87,7 +87,7 @@ export class NotificationService extends BaseService {
this.logger.error(`Unable to run job handler (${job.name}): ${error}`, error?.stack, JSON.stringify(job.data)); this.logger.error(`Unable to run job handler (${job.name}): ${error}`, error?.stack, JSON.stringify(job.data));
switch (job.name) { switch (job.name) {
case JobName.BackupDatabase: { case JobName.DatabaseBackup: {
const errorMessage = error instanceof Error ? error.message : error; const errorMessage = error instanceof Error ? error.message : error;
const item = await this.notificationRepository.create({ const item = await this.notificationRepository.create({
userId: admin.id, userId: admin.id,
@ -135,7 +135,7 @@ export class NotificationService extends BaseService {
@OnEvent({ name: 'AssetShow' }) @OnEvent({ name: 'AssetShow' })
async onAssetShow({ assetId }: ArgOf<'AssetShow'>) { async onAssetShow({ assetId }: ArgOf<'AssetShow'>) {
await this.jobRepository.queue({ name: JobName.GenerateThumbnails, data: { id: assetId, notify: true } }); await this.jobRepository.queue({ name: JobName.AssetGenerateThumbnails, data: { id: assetId, notify: true } });
} }
@OnEvent({ name: 'AssetTrash' }) @OnEvent({ name: 'AssetTrash' })
@ -193,7 +193,7 @@ export class NotificationService extends BaseService {
@OnEvent({ name: 'UserSignup' }) @OnEvent({ name: 'UserSignup' })
async onUserSignup({ notify, id, tempPassword }: ArgOf<'UserSignup'>) { async onUserSignup({ notify, id, tempPassword }: ArgOf<'UserSignup'>) {
if (notify) { if (notify) {
await this.jobRepository.queue({ name: JobName.NotifySignup, data: { id, tempPassword } }); await this.jobRepository.queue({ name: JobName.NotifyUserSignup, data: { id, tempPassword } });
} }
} }
@ -313,8 +313,8 @@ export class NotificationService extends BaseService {
return { name, html: templateResponse }; return { name, html: templateResponse };
} }
@OnJob({ name: JobName.NotifySignup, queue: QueueName.Notification }) @OnJob({ name: JobName.NotifyUserSignup, queue: QueueName.Notification })
async handleUserSignup({ id, tempPassword }: JobOf<JobName.NotifySignup>) { async handleUserSignup({ id, tempPassword }: JobOf<JobName.NotifyUserSignup>) {
const user = await this.userRepository.get(id, { withDeleted: false }); const user = await this.userRepository.get(id, { withDeleted: false });
if (!user) { if (!user) {
return JobStatus.Skipped; return JobStatus.Skipped;

View File

@ -276,7 +276,7 @@ describe(PersonService.name, () => {
}, },
]); ]);
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: 'person-1' }, data: { id: 'person-1' },
}); });
expect(mocks.access.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); expect(mocks.access.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1']));
@ -337,7 +337,7 @@ describe(PersonService.name, () => {
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: personStub.newThumbnail.id }, data: { id: personStub.newThumbnail.id },
}, },
]); ]);
@ -373,7 +373,7 @@ describe(PersonService.name, () => {
await sut.createNewFeaturePhoto([personStub.newThumbnail.id]); await sut.createNewFeaturePhoto([personStub.newThumbnail.id]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.GeneratePersonThumbnail, name: JobName.PersonGenerateThumbnail,
data: { id: personStub.newThumbnail.id }, data: { id: personStub.newThumbnail.id },
}, },
]); ]);
@ -462,7 +462,7 @@ describe(PersonService.name, () => {
expect(mocks.person.vacuum).not.toHaveBeenCalled(); expect(mocks.person.vacuum).not.toHaveBeenCalled();
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.FaceDetection, name: JobName.AssetDetectFaces,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -481,7 +481,7 @@ describe(PersonService.name, () => {
expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.FaceDetection, name: JobName.AssetDetectFaces,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -499,7 +499,7 @@ describe(PersonService.name, () => {
expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(undefined); expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(undefined);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.FaceDetection, name: JobName.AssetDetectFaces,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -518,7 +518,7 @@ describe(PersonService.name, () => {
expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(true); expect(mocks.assetJob.streamForDetectFacesJob).toHaveBeenCalledWith(true);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.FaceDetection, name: JobName.AssetDetectFaces,
data: { id: assetStub.image.id }, data: { id: assetStub.image.id },
}, },
]); ]);
@ -754,7 +754,7 @@ describe(PersonService.name, () => {
expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [], [faceSearch]); expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [], [faceSearch]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.QueueFacialRecognition, data: { force: false } }, { name: JobName.FacialRecognitionQueueAll, data: { force: false } },
{ name: JobName.FacialRecognition, data: { id: faceId } }, { name: JobName.FacialRecognition, data: { id: faceId } },
]); ]);
expect(mocks.person.reassignFace).not.toHaveBeenCalled(); expect(mocks.person.reassignFace).not.toHaveBeenCalled();
@ -790,7 +790,7 @@ describe(PersonService.name, () => {
expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [faceStub.primaryFace1.id], [faceSearch]); expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [faceStub.primaryFace1.id], [faceSearch]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.QueueFacialRecognition, data: { force: false } }, { name: JobName.FacialRecognitionQueueAll, data: { force: false } },
{ name: JobName.FacialRecognition, data: { id: faceId } }, { name: JobName.FacialRecognition, data: { id: faceId } },
]); ]);
expect(mocks.person.reassignFace).not.toHaveBeenCalled(); expect(mocks.person.reassignFace).not.toHaveBeenCalled();
@ -830,7 +830,7 @@ describe(PersonService.name, () => {
expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [], [faceSearch]); expect(mocks.person.refreshFaces).toHaveBeenCalledWith([face], [], [faceSearch]);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ name: JobName.QueueFacialRecognition, data: { force: false } }, { name: JobName.FacialRecognitionQueueAll, data: { force: false } },
{ name: JobName.FacialRecognition, data: { id: faceId } }, { name: JobName.FacialRecognition, data: { id: faceId } },
]); ]);
expect(mocks.person.reassignFace).not.toHaveBeenCalled(); expect(mocks.person.reassignFace).not.toHaveBeenCalled();

View File

@ -140,7 +140,7 @@ export class PersonService extends BaseService {
if (assetFace) { if (assetFace) {
await this.personRepository.update({ id: personId, faceAssetId: assetFace.id }); await this.personRepository.update({ id: personId, faceAssetId: assetFace.id });
jobs.push({ name: JobName.GeneratePersonThumbnail, data: { id: personId } }); jobs.push({ name: JobName.PersonGenerateThumbnail, data: { id: personId } });
} }
} }
@ -211,7 +211,7 @@ export class PersonService extends BaseService {
}); });
if (assetId) { if (assetId) {
await this.jobRepository.queue({ name: JobName.GeneratePersonThumbnail, data: { id } }); await this.jobRepository.queue({ name: JobName.PersonGenerateThumbnail, data: { id } });
} }
return mapPerson(person); return mapPerson(person);
@ -261,8 +261,8 @@ export class PersonService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.QueueFaceDetection, queue: QueueName.FaceDetection }) @OnJob({ name: JobName.AssetDetectFacesQueueAll, queue: QueueName.FaceDetection })
async handleQueueDetectFaces({ force }: JobOf<JobName.QueueFaceDetection>): Promise<JobStatus> { async handleQueueDetectFaces({ force }: JobOf<JobName.AssetDetectFacesQueueAll>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: false }); const { machineLearning } = await this.getConfig({ withCache: false });
if (!isFacialRecognitionEnabled(machineLearning)) { if (!isFacialRecognitionEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;
@ -277,7 +277,7 @@ export class PersonService extends BaseService {
let jobs: JobItem[] = []; let jobs: JobItem[] = [];
const assets = this.assetJobRepository.streamForDetectFacesJob(force); const assets = this.assetJobRepository.streamForDetectFacesJob(force);
for await (const asset of assets) { for await (const asset of assets) {
jobs.push({ name: JobName.FaceDetection, data: { id: asset.id } }); jobs.push({ name: JobName.AssetDetectFaces, data: { id: asset.id } });
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) { if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(jobs); await this.jobRepository.queueAll(jobs);
@ -294,8 +294,8 @@ export class PersonService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.FaceDetection, queue: QueueName.FaceDetection }) @OnJob({ name: JobName.AssetDetectFaces, queue: QueueName.FaceDetection })
async handleDetectFaces({ id }: JobOf<JobName.FaceDetection>): Promise<JobStatus> { async handleDetectFaces({ id }: JobOf<JobName.AssetDetectFaces>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: true }); const { machineLearning } = await this.getConfig({ withCache: true });
if (!isFacialRecognitionEnabled(machineLearning)) { if (!isFacialRecognitionEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;
@ -369,7 +369,7 @@ export class PersonService extends BaseService {
if (facesToAdd.length > 0) { if (facesToAdd.length > 0) {
this.logger.log(`Detected ${facesToAdd.length} new faces in asset ${id}`); this.logger.log(`Detected ${facesToAdd.length} new faces in asset ${id}`);
const jobs = facesToAdd.map((face) => ({ name: JobName.FacialRecognition, data: { id: face.id } }) as const); const jobs = facesToAdd.map((face) => ({ name: JobName.FacialRecognition, data: { id: face.id } }) as const);
await this.jobRepository.queueAll([{ name: JobName.QueueFacialRecognition, data: { force: false } }, ...jobs]); await this.jobRepository.queueAll([{ name: JobName.FacialRecognitionQueueAll, data: { force: false } }, ...jobs]);
} else if (embeddings.length > 0) { } else if (embeddings.length > 0) {
this.logger.log(`Added ${embeddings.length} face embeddings for asset ${id}`); this.logger.log(`Added ${embeddings.length} face embeddings for asset ${id}`);
} }
@ -396,8 +396,8 @@ export class PersonService extends BaseService {
return intersection / union; return intersection / union;
} }
@OnJob({ name: JobName.QueueFacialRecognition, queue: QueueName.FacialRecognition }) @OnJob({ name: JobName.FacialRecognitionQueueAll, queue: QueueName.FacialRecognition })
async handleQueueRecognizeFaces({ force, nightly }: JobOf<JobName.QueueFacialRecognition>): Promise<JobStatus> { async handleQueueRecognizeFaces({ force, nightly }: JobOf<JobName.FacialRecognitionQueueAll>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: false }); const { machineLearning } = await this.getConfig({ withCache: false });
if (!isFacialRecognitionEnabled(machineLearning)) { if (!isFacialRecognitionEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;
@ -526,7 +526,7 @@ export class PersonService extends BaseService {
if (isCore && !personId) { if (isCore && !personId) {
this.logger.log(`Creating new person for face ${id}`); this.logger.log(`Creating new person for face ${id}`);
const newPerson = await this.personRepository.create({ ownerId: face.asset.ownerId, faceAssetId: face.id }); const newPerson = await this.personRepository.create({ ownerId: face.asset.ownerId, faceAssetId: face.id });
await this.jobRepository.queue({ name: JobName.GeneratePersonThumbnail, data: { id: newPerson.id } }); await this.jobRepository.queue({ name: JobName.PersonGenerateThumbnail, data: { id: newPerson.id } });
personId = newPerson.id; personId = newPerson.id;
} }
@ -538,8 +538,8 @@ export class PersonService extends BaseService {
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.MigratePerson, queue: QueueName.Migration }) @OnJob({ name: JobName.PersonFileMigration, queue: QueueName.Migration })
async handlePersonMigration({ id }: JobOf<JobName.MigratePerson>): Promise<JobStatus> { async handlePersonMigration({ id }: JobOf<JobName.PersonFileMigration>): Promise<JobStatus> {
const person = await this.personRepository.getById(id); const person = await this.personRepository.getById(id);
if (!person) { if (!person) {
return JobStatus.Failed; return JobStatus.Failed;

View File

@ -14,7 +14,7 @@ import { BaseService } from 'src/services/base.service';
@Injectable() @Injectable()
export class SessionService extends BaseService { export class SessionService extends BaseService {
@OnJob({ name: JobName.CleanOldSessionTokens, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.SessionCleanup, queue: QueueName.BackgroundTask })
async handleCleanup(): Promise<JobStatus> { async handleCleanup(): Promise<JobStatus> {
const sessions = await this.sessionRepository.cleanup(); const sessions = await this.sessionRepository.cleanup();
for (const session of sessions) { for (const session of sessions) {

View File

@ -64,8 +64,8 @@ export class SmartInfoService extends BaseService {
}); });
} }
@OnJob({ name: JobName.QueueSmartSearch, queue: QueueName.SmartSearch }) @OnJob({ name: JobName.SmartSearchQueueAll, queue: QueueName.SmartSearch })
async handleQueueEncodeClip({ force }: JobOf<JobName.QueueSmartSearch>): Promise<JobStatus> { async handleQueueEncodeClip({ force }: JobOf<JobName.SmartSearchQueueAll>): Promise<JobStatus> {
const { machineLearning } = await this.getConfig({ withCache: false }); const { machineLearning } = await this.getConfig({ withCache: false });
if (!isSmartSearchEnabled(machineLearning)) { if (!isSmartSearchEnabled(machineLearning)) {
return JobStatus.Skipped; return JobStatus.Skipped;

View File

@ -62,8 +62,8 @@ export class StorageService extends BaseService {
}); });
} }
@OnJob({ name: JobName.DeleteFiles, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.FileDelete, queue: QueueName.BackgroundTask })
async handleDeleteFiles(job: JobOf<JobName.DeleteFiles>): Promise<JobStatus> { async handleDeleteFiles(job: JobOf<JobName.FileDelete>): Promise<JobStatus> {
const { files } = job; const { files } = job;
// TODO: one job per file // TODO: one job per file

View File

@ -77,24 +77,24 @@ describe(TrashService.name, () => {
mocks.trash.empty.mockResolvedValue(1); mocks.trash.empty.mockResolvedValue(1);
await expect(sut.empty(authStub.user1)).resolves.toEqual({ count: 1 }); await expect(sut.empty(authStub.user1)).resolves.toEqual({ count: 1 });
expect(mocks.trash.empty).toHaveBeenCalledWith('user-id'); expect(mocks.trash.empty).toHaveBeenCalledWith('user-id');
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueTrashEmpty, data: {} }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetEmptyTrash, data: {} });
}); });
}); });
describe('onAssetsDelete', () => { describe('onAssetsDelete', () => {
it('should queue the empty trash job', async () => { it('should queue the empty trash job', async () => {
await expect(sut.onAssetsDelete()).resolves.toBeUndefined(); await expect(sut.onAssetsDelete()).resolves.toBeUndefined();
expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.QueueTrashEmpty, data: {} }); expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.AssetEmptyTrash, data: {} });
}); });
}); });
describe('handleQueueEmptyTrash', () => { describe('handleQueueEmptyTrash', () => {
it('should queue asset delete jobs', async () => { it('should queue asset delete jobs', async () => {
mocks.trash.getDeletedIds.mockReturnValue(makeAssetIdStream(1)); mocks.trash.getDeletedIds.mockReturnValue(makeAssetIdStream(1));
await expect(sut.handleQueueEmptyTrash()).resolves.toEqual(JobStatus.Success); await expect(sut.handleEmptyTrash()).resolves.toEqual(JobStatus.Success);
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { id: 'asset-1', deleteOnDisk: true }, data: { id: 'asset-1', deleteOnDisk: true },
}, },
]); ]);

View File

@ -35,18 +35,18 @@ export class TrashService extends BaseService {
async empty(auth: AuthDto): Promise<TrashResponseDto> { async empty(auth: AuthDto): Promise<TrashResponseDto> {
const count = await this.trashRepository.empty(auth.user.id); const count = await this.trashRepository.empty(auth.user.id);
if (count > 0) { if (count > 0) {
await this.jobRepository.queue({ name: JobName.QueueTrashEmpty, data: {} }); await this.jobRepository.queue({ name: JobName.AssetEmptyTrash, data: {} });
} }
return { count }; return { count };
} }
@OnEvent({ name: 'AssetDeleteAll' }) @OnEvent({ name: 'AssetDeleteAll' })
async onAssetsDelete() { async onAssetsDelete() {
await this.jobRepository.queue({ name: JobName.QueueTrashEmpty, data: {} }); await this.jobRepository.queue({ name: JobName.AssetEmptyTrash, data: {} });
} }
@OnJob({ name: JobName.QueueTrashEmpty, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.AssetEmptyTrash, queue: QueueName.BackgroundTask })
async handleQueueEmptyTrash() { async handleEmptyTrash() {
const assets = this.trashRepository.getDeletedIds(); const assets = this.trashRepository.getDeletedIds();
let count = 0; let count = 0;
@ -74,7 +74,7 @@ export class TrashService extends BaseService {
this.logger.debug(`Queueing ${ids.length} asset(s) for deletion from the trash`); this.logger.debug(`Queueing ${ids.length} asset(s) for deletion from the trash`);
await this.jobRepository.queueAll( await this.jobRepository.queueAll(
ids.map((assetId) => ({ ids.map((assetId) => ({
name: JobName.AssetDeletion, name: JobName.AssetDelete,
data: { data: {
id: assetId, id: assetId,
deleteOnDisk: true, deleteOnDisk: true,

View File

@ -158,7 +158,7 @@ describe(UserAdminService.name, () => {
deletedAt: expect.any(Date), deletedAt: expect.any(Date),
}); });
expect(mocks.job.queue).toHaveBeenCalledWith({ expect(mocks.job.queue).toHaveBeenCalledWith({
name: JobName.UserDeletion, name: JobName.UserDelete,
data: { id: userStub.user1.id, force: true }, data: { id: userStub.user1.id, force: true },
}); });
}); });

View File

@ -104,7 +104,7 @@ export class UserAdminService extends BaseService {
const user = await this.userRepository.update(id, { status, deletedAt: new Date() }); const user = await this.userRepository.update(id, { status, deletedAt: new Date() });
if (force) { if (force) {
await this.jobRepository.queue({ name: JobName.UserDeletion, data: { id: user.id, force } }); await this.jobRepository.queue({ name: JobName.UserDelete, data: { id: user.id, force } });
} }
return mapUserAdmin(user); return mapUserAdmin(user);

View File

@ -122,7 +122,7 @@ describe(UserService.name, () => {
await sut.createProfileImage(authStub.admin, file); await sut.createProfileImage(authStub.admin, file);
expect(mocks.job.queue.mock.calls).toEqual([[{ name: JobName.DeleteFiles, data: { files } }]]); expect(mocks.job.queue.mock.calls).toEqual([[{ name: JobName.FileDelete, data: { files } }]]);
}); });
it('should not delete the profile image if it has not been set', async () => { it('should not delete the profile image if it has not been set', async () => {
@ -156,7 +156,7 @@ describe(UserService.name, () => {
await sut.deleteProfileImage(authStub.admin); await sut.deleteProfileImage(authStub.admin);
expect(mocks.job.queue.mock.calls).toEqual([[{ name: JobName.DeleteFiles, data: { files } }]]); expect(mocks.job.queue.mock.calls).toEqual([[{ name: JobName.FileDelete, data: { files } }]]);
}); });
}); });
@ -211,7 +211,7 @@ describe(UserService.name, () => {
await sut.handleUserDeleteCheck(); await sut.handleUserDeleteCheck();
expect(mocks.user.getDeletedAfter).toHaveBeenCalled(); expect(mocks.user.getDeletedAfter).toHaveBeenCalled();
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.UserDeletion, data: { id: user.id } }]); expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.UserDelete, data: { id: user.id } }]);
}); });
}); });

View File

@ -99,7 +99,7 @@ export class UserService extends BaseService {
}); });
if (oldpath !== '') { if (oldpath !== '') {
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files: [oldpath] } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [oldpath] } });
} }
return { return {
@ -115,7 +115,7 @@ export class UserService extends BaseService {
throw new BadRequestException("Can't delete a missing profile Image"); throw new BadRequestException("Can't delete a missing profile Image");
} }
await this.userRepository.update(auth.user.id, { profileImagePath: '', profileChangedAt: new Date() }); await this.userRepository.update(auth.user.id, { profileImagePath: '', profileChangedAt: new Date() });
await this.jobRepository.queue({ name: JobName.DeleteFiles, data: { files: [user.profileImagePath] } }); await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [user.profileImagePath] } });
} }
async getProfileImage(id: string): Promise<ImmichFileResponse> { async getProfileImage(id: string): Promise<ImmichFileResponse> {
@ -213,7 +213,7 @@ export class UserService extends BaseService {
}; };
} }
@OnJob({ name: JobName.userSyncUsage, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.UserSyncUsage, queue: QueueName.BackgroundTask })
async handleUserSyncUsage(): Promise<JobStatus> { async handleUserSyncUsage(): Promise<JobStatus> {
await this.userRepository.syncUsage(); await this.userRepository.syncUsage();
return JobStatus.Success; return JobStatus.Success;
@ -223,12 +223,12 @@ export class UserService extends BaseService {
async handleUserDeleteCheck(): Promise<JobStatus> { async handleUserDeleteCheck(): Promise<JobStatus> {
const config = await this.getConfig({ withCache: false }); const config = await this.getConfig({ withCache: false });
const users = await this.userRepository.getDeletedAfter(DateTime.now().minus({ days: config.user.deleteDelay })); const users = await this.userRepository.getDeletedAfter(DateTime.now().minus({ days: config.user.deleteDelay }));
await this.jobRepository.queueAll(users.map((user) => ({ name: JobName.UserDeletion, data: { id: user.id } }))); await this.jobRepository.queueAll(users.map((user) => ({ name: JobName.UserDelete, data: { id: user.id } })));
return JobStatus.Success; return JobStatus.Success;
} }
@OnJob({ name: JobName.UserDeletion, queue: QueueName.BackgroundTask }) @OnJob({ name: JobName.UserDelete, queue: QueueName.BackgroundTask })
async handleUserDelete({ id, force }: JobOf<JobName.UserDeletion>): Promise<JobStatus> { async handleUserDelete({ id, force }: JobOf<JobName.UserDelete>): Promise<JobStatus> {
const config = await this.getConfig({ withCache: false }); const config = await this.getConfig({ withCache: false });
const user = await this.userRepository.get(id, { withDeleted: true }); const user = await this.userRepository.get(id, { withDeleted: true });
if (!user) { if (!user) {

View File

@ -41,7 +41,7 @@ export class VersionService extends BaseService {
const needsNewMemories = semver.lt(previousVersion, '1.129.0'); const needsNewMemories = semver.lt(previousVersion, '1.129.0');
if (needsNewMemories) { if (needsNewMemories) {
await this.jobRepository.queue({ name: JobName.MemoriesCreate }); await this.jobRepository.queue({ name: JobName.MemoryGenerate });
} }
} }
}); });

View File

@ -273,93 +273,93 @@ export interface QueueStatus {
export type JobItem = export type JobItem =
// Backups // Backups
| { name: JobName.BackupDatabase; data?: IBaseJob } | { name: JobName.DatabaseBackup; data?: IBaseJob }
// Transcoding // Transcoding
| { name: JobName.QueueVideoConversion; data: IBaseJob } | { name: JobName.AssetEncodeVideoQueueAll; data: IBaseJob }
| { name: JobName.VideoConversation; data: IEntityJob } | { name: JobName.AssetEncodeVideo; data: IEntityJob }
// Thumbnails // Thumbnails
| { name: JobName.QueueGenerateThumbnails; data: IBaseJob } | { name: JobName.AssetGenerateThumbnailsQueueAll; data: IBaseJob }
| { name: JobName.GenerateThumbnails; data: IEntityJob } | { name: JobName.AssetGenerateThumbnails; data: IEntityJob }
// User // User
| { name: JobName.UserDeleteCheck; data?: IBaseJob } | { name: JobName.UserDeleteCheck; data?: IBaseJob }
| { name: JobName.UserDeletion; data: IEntityJob } | { name: JobName.UserDelete; data: IEntityJob }
| { name: JobName.userSyncUsage; data?: IBaseJob } | { name: JobName.UserSyncUsage; data?: IBaseJob }
// Storage Template // Storage Template
| { name: JobName.StorageTemplateMigration; data?: IBaseJob } | { name: JobName.StorageTemplateMigration; data?: IBaseJob }
| { name: JobName.StorageTemplateMigrationSingle; data: IEntityJob } | { name: JobName.StorageTemplateMigrationSingle; data: IEntityJob }
// Migration // Migration
| { name: JobName.QueueMigration; data?: IBaseJob } | { name: JobName.FileMigrationQueueAll; data?: IBaseJob }
| { name: JobName.MigrateAsset; data: IEntityJob } | { name: JobName.AssetFileMigration; data: IEntityJob }
| { name: JobName.MigratePerson; data: IEntityJob } | { name: JobName.PersonFileMigration; data: IEntityJob }
// Metadata Extraction // Metadata Extraction
| { name: JobName.QueueMetadataExtraction; data: IBaseJob } | { name: JobName.AssetExtractMetadataQueueAll; data: IBaseJob }
| { name: JobName.MetadataExtraction; data: IEntityJob } | { name: JobName.AssetExtractMetadata; data: IEntityJob }
// Notifications // Notifications
| { name: JobName.NotificationsCleanup; data?: IBaseJob } | { name: JobName.NotificationsCleanup; data?: IBaseJob }
// Sidecar Scanning // Sidecar Scanning
| { name: JobName.QueueSidecar; data: IBaseJob } | { name: JobName.SidecarQueueAll; data: IBaseJob }
| { name: JobName.SidecarDiscovery; data: IEntityJob } | { name: JobName.SidecarDiscovery; data: IEntityJob }
| { name: JobName.SidecarSync; data: IEntityJob } | { name: JobName.SidecarSync; data: IEntityJob }
| { name: JobName.SidecarWrite; data: ISidecarWriteJob } | { name: JobName.SidecarWrite; data: ISidecarWriteJob }
// Facial Recognition // Facial Recognition
| { name: JobName.QueueFaceDetection; data: IBaseJob } | { name: JobName.AssetDetectFacesQueueAll; data: IBaseJob }
| { name: JobName.FaceDetection; data: IEntityJob } | { name: JobName.AssetDetectFaces; data: IEntityJob }
| { name: JobName.QueueFacialRecognition; data: INightlyJob } | { name: JobName.FacialRecognitionQueueAll; data: INightlyJob }
| { name: JobName.FacialRecognition; data: IDeferrableJob } | { name: JobName.FacialRecognition; data: IDeferrableJob }
| { name: JobName.GeneratePersonThumbnail; data: IEntityJob } | { name: JobName.PersonGenerateThumbnail; data: IEntityJob }
// Smart Search // Smart Search
| { name: JobName.QueueSmartSearch; data: IBaseJob } | { name: JobName.SmartSearchQueueAll; data: IBaseJob }
| { name: JobName.SmartSearch; data: IEntityJob } | { name: JobName.SmartSearch; data: IEntityJob }
| { name: JobName.QueueTrashEmpty; data?: IBaseJob } | { name: JobName.AssetEmptyTrash; data?: IBaseJob }
// Duplicate Detection // Duplicate Detection
| { name: JobName.QueueDuplicateDetection; data: IBaseJob } | { name: JobName.AssetDetectDuplicatesQueueAll; data: IBaseJob }
| { name: JobName.DuplicateDetection; data: IEntityJob } | { name: JobName.AssetDetectDuplicates; data: IEntityJob }
// Memories // Memories
| { name: JobName.MemoriesCleanup; data?: IBaseJob } | { name: JobName.MemoryCleanup; data?: IBaseJob }
| { name: JobName.MemoriesCreate; data?: IBaseJob } | { name: JobName.MemoryGenerate; data?: IBaseJob }
// Filesystem // Filesystem
| { name: JobName.DeleteFiles; data: IDeleteFilesJob } | { name: JobName.FileDelete; data: IDeleteFilesJob }
// Cleanup // Cleanup
| { name: JobName.CleanOldAuditLogs; data?: IBaseJob } | { name: JobName.AuditLogCleanup; data?: IBaseJob }
| { name: JobName.CleanOldSessionTokens; data?: IBaseJob } | { name: JobName.SessionCleanup; data?: IBaseJob }
// Tags // Tags
| { name: JobName.TagCleanup; data?: IBaseJob } | { name: JobName.TagCleanup; data?: IBaseJob }
// Asset Deletion // Asset Deletion
| { name: JobName.PersonCleanup; data?: IBaseJob } | { name: JobName.PersonCleanup; data?: IBaseJob }
| { name: JobName.AssetDeletion; data: IAssetDeleteJob } | { name: JobName.AssetDelete; data: IAssetDeleteJob }
| { name: JobName.AssetDeletionCheck; data?: IBaseJob } | { name: JobName.AssetDeleteCheck; data?: IBaseJob }
// Library Management // Library Management
| { name: JobName.LibrarySyncFiles; data: ILibraryFileJob } | { name: JobName.LibrarySyncFiles; data: ILibraryFileJob }
| { name: JobName.LibraryQueueSyncFiles; data: IEntityJob } | { name: JobName.LibrarySyncFilesQueueAll; data: IEntityJob }
| { name: JobName.LibraryQueueSyncAssets; data: IEntityJob } | { name: JobName.LibrarySyncAssetsQueueAll; data: IEntityJob }
| { name: JobName.LibrarySyncAssets; data: ILibraryBulkIdsJob } | { name: JobName.LibrarySyncAssets; data: ILibraryBulkIdsJob }
| { name: JobName.LibraryAssetRemoval; data: ILibraryFileJob } | { name: JobName.LibraryRemoveAsset; data: ILibraryFileJob }
| { name: JobName.LibraryDelete; data: IEntityJob } | { name: JobName.LibraryDelete; data: IEntityJob }
| { name: JobName.LibraryQueueScanAll; data?: IBaseJob } | { name: JobName.LibraryScanQueueAll; data?: IBaseJob }
| { name: JobName.LibraryQueueCleanup; data: IBaseJob } | { name: JobName.LibraryDeleteCheck; data: IBaseJob }
// Notification // Notification
| { name: JobName.SendMail; data: IEmailJob } | { name: JobName.SendMail; data: IEmailJob }
| { name: JobName.NotifyAlbumInvite; data: INotifyAlbumInviteJob } | { name: JobName.NotifyAlbumInvite; data: INotifyAlbumInviteJob }
| { name: JobName.NotifyAlbumUpdate; data: INotifyAlbumUpdateJob } | { name: JobName.NotifyAlbumUpdate; data: INotifyAlbumUpdateJob }
| { name: JobName.NotifySignup; data: INotifySignupJob } | { name: JobName.NotifyUserSignup; data: INotifySignupJob }
// Version check // Version check
| { name: JobName.VersionCheck; data: IBaseJob }; | { name: JobName.VersionCheck; data: IBaseJob };

View File

@ -150,7 +150,7 @@ describe(UserService.name, () => {
const { user } = await ctx.newUser({ deletedAt: DateTime.now().minus({ days: 60 }).toJSDate() }); const { user } = await ctx.newUser({ deletedAt: DateTime.now().minus({ days: 60 }).toJSDate() });
jobMock.queueAll.mockResolvedValue(void 0); jobMock.queueAll.mockResolvedValue(void 0);
await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.Success); await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.Success);
expect(jobMock.queueAll).toHaveBeenCalledExactlyOnceWith([{ name: JobName.UserDeletion, data: { id: user.id } }]); expect(jobMock.queueAll).toHaveBeenCalledExactlyOnceWith([{ name: JobName.UserDelete, data: { id: user.id } }]);
}); });
it('should skip a recently deleted user', async () => { it('should skip a recently deleted user', async () => {

View File

@ -53,7 +53,7 @@ describe(VersionService.name, () => {
await versionHistoryRepo.create({ version: 'v1.128.0' }); await versionHistoryRepo.create({ version: 'v1.128.0' });
await sut.onBootstrap(); await sut.onBootstrap();
expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.MemoriesCreate }); expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.MemoryGenerate });
}); });
it('should not queue memory creation when upgrading from 1.129.0', async () => { it('should not queue memory creation when upgrading from 1.129.0', async () => {