← back to Vendor Recrawl Dispatcher

lib/resolve-pipeline.js

63 lines

'use strict';
// Resolve a vendor row -> the canonical refresh pipeline to run.
//
// The canonical pattern is scripts/<name>-refresh/run.sh (WallQuest is the
// reference), which does: scrape -> write dw_unified staging -> price-finder -> CNCP.
// NO publish.
//
// HARD RULE (constraint): if no refresh pipeline is resolvable for a vendor, the
// dispatcher must SKIP + LOG it, never crash and never publish. As dedicated
// <code>-refresh/ dirs get built (each vendor has its own *-scraper-manager skill),
// they are auto-discovered here.
const fs = require('fs');
const path = require('path');
const cfg = require('./config');

// Candidate directory names to probe for a per-vendor refresh script, derived
// from vendor_code and pm2_name (both dash/underscore variants).
function candidateNames(v) {
  const out = new Set();
  const push = (s) => { if (s) { out.add(s); out.add(s.replace(/_/g, '-')); out.add(s.replace(/-/g, '')); } };
  push(v.vendor_code);
  if (v.pm2_name) push(v.pm2_name.replace(/-agent$/, ''));
  return [...out];
}

// Returns { kind, cmd, cwd, reason }.
//   kind = 'refresh-script'  -> runnable bash run.sh
//   kind = 'unresolved'      -> no pipeline; caller SKIPS + logs
const DISPATCHER_ROOT = path.join(__dirname, '..');

function resolve(v) {
  // 1. Hand-wired <code>-refresh/run.sh takes PRIORITY (Thibaut-style, for hard vendors).
  for (const name of candidateNames(v)) {
    const dir = path.join(cfg.REFRESH_SCRIPTS_DIR, `${name}-refresh`);
    const runSh = path.join(dir, 'run.sh');
    try {
      if (fs.existsSync(runSh)) {
        return { kind: 'refresh-script', cmd: ['/bin/bash', runSh], cwd: dir, reason: `${name}-refresh/run.sh` };
      }
    } catch (_) { /* keep probing */ }
  }
  // 2. GENERIC product_url refresher (DTD Option C) — covers any vendor with a catalog_table.
  //    Fetch each existing SKU's product_url (free) -> extract via LOCAL models ($0) -> update
  //    staging. The generic refresher self-skips if the table has no product_url column/rows.
  if (v.catalog_table && /^[a-z0-9_]+$/i.test(v.catalog_table)) {
    const limit = cfg.GENERIC_LIMIT || 25;
    return {
      kind: 'refresh-script',
      cmd: ['node', 'lib/generic-url-refresh.js', v.catalog_table, v.vendor_name, String(limit), '--run'],
      cwd: DISPATCHER_ROOT,
      reason: `generic product_url refresh (${v.catalog_table})`,
    };
  }
  return {
    kind: 'unresolved',
    cmd: null,
    cwd: null,
    reason: `no <code>-refresh/run.sh and no catalog_table for vendor_code=${v.vendor_code}`,
  };
}

module.exports = { resolve, candidateNames };