feat: run durable image worker locally
Quality / test (push) Canceled after 0s

This commit is contained in:
2026-09-08 22:06:28 -04:00
parent abd574293b
commit dd8af7c140
6 changed files with 108 additions and 2 deletions
@@ -110,4 +110,21 @@ export async function runImageDerivativeJob({ job, loadSource, processor }) {
failedAt: new Date(),
};
}
}
export async function processNextPersistentImageDerivativeJob({ jobRepository, loadSource, processor }) {
const claimed = await jobRepository.claimNext();
if (!claimed) return null;
const job = { ...claimed, type: 'IMAGE_DERIVATIVES' };
const result = await runImageDerivativeJob({ job, loadSource, processor });
if (result.status === 'COMPLETED') {
await jobRepository.complete(claimed.id, result.derivatives);
} else {
await jobRepository.fail(claimed.id, result.error);
}
return result;
}
+50
View File
@@ -0,0 +1,50 @@
import dotenv from 'dotenv';
import { fileURLToPath } from 'node:url';
dotenv.config({ path: fileURLToPath(new URL('../../../.env', import.meta.url)) });
import { createDatabase } from '../../api/src/infrastructure/database/client.js';
import { createLocalImageStorage } from '../../api/src/infrastructure/images/local-image-storage.js';
import { createImageDerivativeProcessor } from '../../api/src/infrastructure/images/image-derivative-processor.js';
import { createSharpImageRenderer } from '../../api/src/infrastructure/images/sharp-image-renderer.js';
import { createImageDerivativeJobRepository } from '../../api/src/modules/inventory/repositories/image-derivative-job-repository.js';
import { processNextPersistentImageDerivativeJob } from './image-derivative-worker.js';
const pollIntervalMs = Number.parseInt(process.env.WORKER_POLL_INTERVAL_MS ?? '2000', 10);
async function runWorker() {
const database = createDatabase();
const imageStorage = createLocalImageStorage(process.env.IMAGE_STORAGE_ROOT ?? '.local/image-storage');
const jobRepository = createImageDerivativeJobRepository(database.db);
const processor = createImageDerivativeProcessor({
imageStorage,
renderer: createSharpImageRenderer(),
});
async function processOne() {
const result = await processNextPersistentImageDerivativeJob({
jobRepository,
async loadSource(sourceKey) {
return { sourceKey, data: await imageStorage.get(sourceKey) };
},
processor,
});
if (result) console.log(`Image derivative job ${result.id} ${result.status.toLowerCase()}.`);
}
await processOne();
const timer = setInterval(() => processOne().catch((error) => console.error(error)), pollIntervalMs);
const shutdown = async () => {
clearInterval(timer);
await database.close();
};
process.once('SIGINT', shutdown);
process.once('SIGTERM', shutdown);
}
runWorker().catch((error) => {
console.error(error);
process.exitCode = 1;
});