Files
picpeak/backend/__tests__/services/imageProcessor.sharpConfig.test.js
T
Paul Nothaft 8337a716b1 fix(file-watcher): bound concurrent photo processing (#846)
* fix(file-watcher): bound concurrent photo processing

chokidar fires 'add' once per file — with no ignoreInitial option the
boot scan fires it for every existing file, and a bulk drop into the
watch folder fires it for every new one at once. Each handler runs DB
lookups plus (for new files) a full sharp pipeline; sharp.concurrency(2)
only caps libvips threads WITHIN one operation, not the number of
parallel pipelines, so unbounded handlers can OOM small hosts.

Gate both 'add' and 'unlink' through a shared p-limit
(FILE_WATCHER_CONCURRENCY, default 2, floor 1) — mass deletes otherwise
burst DB work and ZIP-cache invalidation the same way. p-limit is pinned
to ^3.1.0, the last CommonJS release.

Adapted from the filpgame fork (426ca491) — thanks @filpgame; extended
to cover 'unlink', documented in .env.example, plus a lock-in test for
the existing Sharp cache/concurrency caps this bound relies on.

* chore(compose): pass FILE_WATCHER_CONCURRENCY into the backend container (codex review of #846)

The backend service uses an explicit environment list (no env_file), so
the documented override never reached the container in the default
compose deployments. Added to both compose files + root .env.example.
2026-07-19 22:00:46 +02:00

31 lines
913 B
JavaScript

/**
* Locks the process-wide Sharp memory guards. The file-watcher concurrency
* bound (FILE_WATCHER_CONCURRENCY) assumes these caps stay in place — they
* limit libvips threads/cache WITHIN one operation while p-limit bounds the
* number of parallel pipelines. From the filpgame fork (426ca491).
*/
const mockSharp = jest.fn();
mockSharp.cache = jest.fn();
mockSharp.concurrency = jest.fn();
jest.mock('sharp', () => mockSharp);
jest.mock('../../src/utils/logger', () => ({
error: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
debug: jest.fn(),
}));
describe('imageProcessor Sharp configuration', () => {
it('disables the Sharp cache and caps libvips concurrency', () => {
jest.isolateModules(() => {
require('../../src/services/imageProcessor');
});
expect(mockSharp.cache).toHaveBeenCalledWith(false);
expect(mockSharp.concurrency).toHaveBeenCalledWith(2);
});
});