feat(assets): add POST /:id/retry to re-queue errored assets
Assets stuck in status='error' had no recovery path without manual DB edits. Adds a retry endpoint that re-dispatches the proxy job, which chains into thumbnail generation automatically and restores the asset to 'processing' → 'ready' without operator intervention.
This commit is contained in:
parent
2bb731c7fc
commit
d3e12deb18
1 changed files with 44 additions and 0 deletions
|
|
@ -15,6 +15,10 @@ const parseRedisUrl = (url) => {
|
|||
return { host: parsed.hostname, port: parseInt(parsed.port, 10) };
|
||||
};
|
||||
|
||||
const proxyQueue = new Queue('proxy', {
|
||||
connection: parseRedisUrl(process.env.REDIS_URL || 'redis://queue:6379'),
|
||||
});
|
||||
|
||||
const thumbnailQueue = new Queue('thumbnail', {
|
||||
connection: parseRedisUrl(process.env.REDIS_URL || 'redis://queue:6379'),
|
||||
});
|
||||
|
|
@ -324,6 +328,46 @@ router.post('/:id/copy', async (req, res, next) => {
|
|||
}
|
||||
});
|
||||
|
||||
// POST /:id/retry - Re-queue proxy generation for an asset stuck in error state
|
||||
//
|
||||
// Proxy failures leave assets at status='error' with no recovery path from the
|
||||
// UI. This endpoint re-dispatches the proxy job so the worker chain
|
||||
// (proxy → thumbnail) runs again without manual DB edits.
|
||||
router.post('/:id/retry', async (req, res, next) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const r = await pool.query('SELECT * FROM assets WHERE id = $1', [id]);
|
||||
if (r.rows.length === 0) return res.status(404).json({ error: 'Asset not found' });
|
||||
const asset = r.rows[0];
|
||||
|
||||
if (asset.status !== 'error') {
|
||||
return res.status(400).json({ error: `Asset is not in error state (current: ${asset.status})` });
|
||||
}
|
||||
if (!asset.original_s3_key) {
|
||||
return res.status(400).json({ error: 'Asset has no source file to reprocess' });
|
||||
}
|
||||
|
||||
// Re-use the existing proxy key if one was partially written; otherwise
|
||||
// construct the canonical key so the worker chain writes to the right place.
|
||||
const proxyKey = asset.proxy_s3_key || `proxies/${id}.mp4`;
|
||||
|
||||
await proxyQueue.add('generate', {
|
||||
assetId: id,
|
||||
inputKey: asset.original_s3_key,
|
||||
outputKey: proxyKey,
|
||||
});
|
||||
|
||||
const updated = await pool.query(
|
||||
`UPDATE assets SET status = 'processing', updated_at = NOW() WHERE id = $1 RETURNING *`,
|
||||
[id]
|
||||
);
|
||||
|
||||
res.json(updated.rows[0]);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /:id - Soft or hard delete
|
||||
router.delete('/:id', async (req, res, next) => {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in a new issue