0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-02-18 01:24:26 -05:00

feat: add job ids

This commit is contained in:
Jonathan Jogenfors 2025-02-07 23:19:41 +01:00
parent c5360e78c5
commit 00ec2bd525
4 changed files with 25 additions and 16 deletions

View file

@ -144,7 +144,6 @@ export interface IAssetDeleteJob extends IEntityJob {
}
export interface ILibraryFileJob extends IEntityJob {
ownerId: string;
assetPath: string;
}

View file

@ -216,6 +216,17 @@ export class JobRepository implements IJobRepository {
private getJobOptions(item: JobItem): JobsOptions | null {
switch (item.name) {
case JobName.LIBRARY_QUEUE_SYNC_ASSETS:
case JobName.LIBRARY_QUEUE_SYNC_FILES:
case JobName.LIBRARY_SYNC_ASSET:
case JobName.LIBRARY_DELETE:
case JobName.SIDECAR_SYNC:
case JobName.SIDECAR_DISCOVERY: {
return { jobId: `${item.data.id}-${item.name}` };
}
case JobName.LIBRARY_SYNC_FILE: {
return { jobId: `${item.data.id}-${item.data.assetPath}` };
}
case JobName.NOTIFY_ALBUM_UPDATE: {
return { jobId: item.data.id, delay: item.data?.delay };
}
@ -228,6 +239,11 @@ export class JobRepository implements IJobRepository {
case JobName.QUEUE_FACIAL_RECOGNITION: {
return { jobId: JobName.QUEUE_FACIAL_RECOGNITION };
}
case JobName.LIBRARY_QUEUE_SYNC_ALL:
case JobName.LIBRARY_QUEUE_CLEANUP: {
// These jobs are globally unique and should only have one instance running at a time
return { jobId: item.name };
}
default: {
return null;
}

View file

@ -181,7 +181,6 @@ describe(LibraryService.name, () => {
name: JobName.LIBRARY_SYNC_FILE,
data: {
id: libraryStub.externalLibrary1.id,
ownerId: libraryStub.externalLibrary1.owner.id,
assetPath: '/data/user1/photo.jpg',
},
},
@ -401,7 +400,6 @@ describe(LibraryService.name, () => {
it('should import a new asset', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: '/data/user1/photo.jpg',
};
@ -445,7 +443,6 @@ describe(LibraryService.name, () => {
it('should import a new video', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: '/data/user1/video.mp4',
};
@ -489,7 +486,6 @@ describe(LibraryService.name, () => {
it('should not import an asset to a soft deleted library', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: '/data/user1/photo.jpg',
};
@ -504,7 +500,6 @@ describe(LibraryService.name, () => {
it('should not refresh a file whose mtime matches existing asset', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: assetStub.hasFileExtension.originalPath,
};
@ -522,10 +517,9 @@ describe(LibraryService.name, () => {
expect(jobMock.queueAll).not.toHaveBeenCalled();
});
it('should skip existing asset', async () => {
it('should skip an existing asset', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: '/data/user1/photo.jpg',
};
@ -537,7 +531,6 @@ describe(LibraryService.name, () => {
it('should not refresh an asset trashed by user', async () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: mockUser.id,
assetPath: assetStub.hasFileExtension.originalPath,
};
@ -554,7 +547,6 @@ describe(LibraryService.name, () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: userStub.admin.id,
assetPath: '/data/user1/photo.jpg',
};
@ -572,7 +564,6 @@ describe(LibraryService.name, () => {
const mockLibraryJob: ILibraryFileJob = {
id: libraryStub.externalLibrary1.id,
ownerId: userStub.admin.id,
assetPath: '/data/user1/photo.jpg',
};
@ -923,7 +914,6 @@ describe(LibraryService.name, () => {
data: {
id: libraryStub.externalLibraryWithImportPaths1.id,
assetPath: '/foo/photo.jpg',
ownerId: libraryStub.externalLibraryWithImportPaths1.owner.id,
},
},
]);
@ -948,7 +938,6 @@ describe(LibraryService.name, () => {
data: {
id: libraryStub.externalLibraryWithImportPaths1.id,
assetPath: '/foo/photo.jpg',
ownerId: libraryStub.externalLibraryWithImportPaths1.owner.id,
},
},
]);

View file

@ -228,14 +228,13 @@ export class LibraryService extends BaseService {
return mapLibrary(library);
}
private async syncFiles({ id, ownerId }: LibraryEntity, assetPaths: string[]) {
private async syncFiles({ id }: LibraryEntity, assetPaths: string[]) {
await this.jobRepository.queueAll(
assetPaths.map((assetPath) => ({
name: JobName.LIBRARY_SYNC_FILE,
data: {
id,
assetPath,
ownerId,
},
})),
);
@ -401,7 +400,7 @@ export class LibraryService extends BaseService {
const mtime = stat.mtime;
asset = await this.assetRepository.create({
ownerId: job.ownerId,
ownerId: library.ownerId,
libraryId: job.id,
checksum: pathHash,
originalPath: assetPath,
@ -433,12 +432,18 @@ export class LibraryService extends BaseService {
async queueScan(id: string) {
await this.findOrFail(id);
// We purge any existing scan jobs for this library. This is because the scan settings
// might have changed and the user wants to start a new scan with these settings.
await this.jobRepository.removeJob(id, JobName.LIBRARY_QUEUE_SYNC_FILES);
await this.jobRepository.removeJob(id, JobName.LIBRARY_QUEUE_SYNC_ASSETS);
await this.jobRepository.queue({
name: JobName.LIBRARY_QUEUE_SYNC_FILES,
data: {
id,
},
});
await this.jobRepository.queue({ name: JobName.LIBRARY_QUEUE_SYNC_ASSETS, data: { id } });
}