feat: add price-check orchestration with retry-safe error handling
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
async function checkProduct(product, deps) {
|
||||
const { fetchAndExtractPrice, sendMail, recordCheckSuccess, recordCheckFailure, now } = deps;
|
||||
const result = await fetchAndExtractPrice(product.url);
|
||||
|
||||
if (result.error) {
|
||||
recordCheckFailure(product.id, 'fetch_error');
|
||||
return { status: 'fetch_error' };
|
||||
}
|
||||
if (result.price == null) {
|
||||
recordCheckFailure(product.id, 'not_found');
|
||||
return { status: 'not_found' };
|
||||
}
|
||||
|
||||
const isBaseline = product.last_price == null;
|
||||
const changed = !isBaseline && result.price !== product.last_price;
|
||||
|
||||
if (changed) {
|
||||
try {
|
||||
await sendMail({
|
||||
name: product.name,
|
||||
url: product.url,
|
||||
oldPrice: product.last_price,
|
||||
newPrice: result.price,
|
||||
});
|
||||
} catch {
|
||||
recordCheckFailure(product.id, 'mail_error');
|
||||
return { status: 'mail_error' };
|
||||
}
|
||||
}
|
||||
|
||||
recordCheckSuccess(product.id, { price: result.price, checkedAt: now() });
|
||||
return { status: 'ok', changed };
|
||||
}
|
||||
|
||||
async function checkAllProducts(products, deps) {
|
||||
const results = [];
|
||||
for (const product of products) {
|
||||
try {
|
||||
const result = await checkProduct(product, deps);
|
||||
results.push({ productId: product.id, ...result });
|
||||
} catch (err) {
|
||||
results.push({ productId: product.id, status: 'error', error: err });
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
module.exports = { checkProduct, checkAllProducts };
|
||||
Reference in New Issue
Block a user