fix(memories): log capture reconfirm failures through the Nest logger

Keeps the no-console and test-new-service ratchets at their baselines: the
reconfirm tests build the service through the suite's existing helper.
This commit is contained in:
Maurice
2026-11-09 11:32:27 +01:00
parent 12caa7fbde
commit a9bfcd0fd5
2 changed files with 16 additions and 14 deletions
@@ -2,7 +2,7 @@ import { TrekPhotoRegistrationService } from '../photos/trek-photo-registration.
import { StorageService } from '../storage/storage.service';
import { exifCaptureInstant } from './memories.helpers';
import { PhotoResolverService } from './photo-resolver.service';
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import exifr from 'exifr';
@@ -95,6 +95,8 @@ interface LookupSlots {
*/
@Injectable()
export class PhotoCaptureBackfillService {
private readonly logger = new Logger(PhotoCaptureBackfillService.name);
/**
* Open lookups per user, never above BACKFILL_CONCURRENCY for any of them. An
* entry lives only while its user has a lookup open or waiting, so the map
@@ -234,7 +236,7 @@ export class PhotoCaptureBackfillService {
});
return changed ? 'changed' : 'same';
} catch (err) {
console.error(`[Photos] capture reconfirm failed for ${id}:`, err instanceof Error ? err.message : err);
this.logger.warn(`capture reconfirm failed for ${id}: ${err instanceof Error ? err.message : String(err)}`);
return 'failed';
}
}
@@ -31,17 +31,24 @@ type Row = {
lng?: number | null;
};
function build(rows: Row[], info: Record<number, unknown>) {
function build(
rows: Row[],
info: Record<number, unknown>,
extra: { getPhotoInfo?: (...args: unknown[]) => Promise<unknown>; photos?: Record<string, unknown> } = {},
) {
const recordCaptureMetadata = vi.fn();
// Keyed on the SECOND argument on purpose: the resolver's signature is
// (userId, photoId), and a mock that keys on the first one passes just as
// happily when the two are swapped at the call site.
const getPhotoInfo = vi.fn(async (_userId: number, id: number) =>
info[id] ? { success: true, data: info[id] } : { success: false, error: 'nope', status: 404 },
const getPhotoInfo = vi.fn(
extra.getPhotoInfo ??
(async (_userId: number, id: number) =>
info[id] ? { success: true, data: info[id] } : { success: false, error: 'nope', status: 404 }),
);
const photos = {
resolve: (id: number) => rows.find((r) => r.id === id) ?? null,
recordCaptureMetadata,
...extra.photos,
} as unknown as TrekPhotoRegistrationService;
const resolver = { getPhotoInfo } as unknown as PhotoResolverService;
return { svc: new PhotoCaptureBackfillService(resolver, photos, storageStub), recordCaptureMetadata, getPhotoInfo };
@@ -527,13 +534,7 @@ describe('PhotoCaptureBackfillService — local files', () => {
describe('PhotoCaptureBackfillService.reconfirm', () => {
function buildReconfirm(answer: () => Promise<unknown>, changed = true) {
const replaceCaptureMetadata = vi.fn(async () => changed);
const getPhotoInfo = vi.fn(answer);
const photos = { replaceCaptureMetadata } as unknown as TrekPhotoRegistrationService;
const svc = new PhotoCaptureBackfillService(
{ getPhotoInfo } as unknown as PhotoResolverService,
photos,
storageStub,
);
const { svc, getPhotoInfo } = build([], {}, { getPhotoInfo: answer, photos: { replaceCaptureMetadata } });
return { svc, replaceCaptureMetadata, getPhotoInfo };
}
@@ -560,11 +561,10 @@ describe('PhotoCaptureBackfillService.reconfirm', () => {
expect(await unconfirmed.svc.reconfirm(7, 3)).toBe('failed');
expect(unconfirmed.replaceCaptureMetadata).not.toHaveBeenCalled();
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const throwing = buildReconfirm(async () => {
throw new Error('NAS gone');
});
expect(await throwing.svc.reconfirm(7, 3)).toBe('failed');
errSpy.mockRestore();
expect(throwing.replaceCaptureMetadata).not.toHaveBeenCalled();
});
});