{"version":3,"file":"worker.mjs","names":[],"sources":["../../../../src/commands/admin/chunk-csv/worker.ts"],"sourcesContent":["import {\n  chunkOneCsvFile,\n  extractErrorMessage,\n  CHILD_FLAG,\n  type ToWorker,\n} from '@transcend-io/utils';\n\nimport { logger } from '../../../logger.js';\n\n/**\n * A unit of work: instructs a worker to chunk a single CSV file.\n */\nexport type ChunkTask = {\n  /** Absolute path of the CSV file to chunk. */\n  filePath: string;\n  /** Options controlling output and chunk size. */\n  options: {\n    /** Optional directory where chunked output files should be written. */\n    outputDir?: string;\n    /** Whether to clear any pre-existing output chunks before writing new ones. */\n    clearOutputDir: boolean;\n    /** Approximate target chunk size in MB (well under Node’s string size limits). */\n    chunkSizeMB: number;\n  };\n};\n\n/**\n * Per-worker progress snapshot for the chunk-csv command.\n */\nexport type ChunkProgress = {\n  /** File being processed by the worker. */\n  filePath: string;\n  /** Number of rows processed so far. */\n  processed: number;\n  /** Optional total rows in the file (not always known). */\n  total?: number;\n};\n\n/**\n * Worker result message once a file has finished processing.\n */\nexport type ChunkResult = {\n  /** Whether the file completed successfully. */\n  ok: boolean;\n  /** File path for which this result applies. */\n  filePath: string;\n  /** Optional error message if the file failed to chunk. */\n  error?: string;\n};\n\n/**\n * Worker entrypoint.\n *\n * Lifecycle:\n * 1) Announce readiness to the parent via `{ type: 'ready' }`.\n * 2) Wait for `{ type: 'task' }` messages; for each, call `chunkOneCsvFile(...)`.\n *    - While chunking, forward progress to the parent via `{ type: 'progress' }`.\n *    - On completion, send `{ type: 'result', ok: true }`.\n *    - On error, send `{ type: 'result', ok: false, error }` and exit(1).\n * 3) On `{ type: 'shutdown' }`, exit(0) gracefully.\n *\n * Notes:\n * - This process is typically spawned by a pool manager that assigns file paths to workers.\n * - The long-lived promise at the end keeps the worker alive between tasks until the parent\n *   sends an explicit shutdown.\n */\nexport async function runChild(): Promise<void> {\n  const workerId = Number(process.env.WORKER_ID || '0');\n  logger.info(`[w${workerId}] ready pid=${process.pid}`);\n\n  // Notify the parent that the worker is ready to receive tasks.\n  process.send?.({ type: 'ready' });\n\n  // Main message loop: receive tasks and shutdown requests from the parent.\n  process.on('message', async (msg: ToWorker<ChunkTask>) => {\n    if (!msg || typeof msg !== 'object') return;\n\n    // Graceful shutdown: let the parent control lifecycle.\n    if (msg.type === 'shutdown') {\n      process.exit(0);\n    }\n\n    // Only handle task messages here.\n    if (msg.type !== 'task') return;\n\n    const { filePath, options } = msg.payload;\n    const { outputDir, clearOutputDir, chunkSizeMB } = options;\n\n    try {\n      // Stream the input CSV and write chunk files asynchronously.\n      await chunkOneCsvFile({\n        filePath,\n        outputDir,\n        clearOutputDir,\n        chunkSizeMB,\n        logger,\n        onProgress: (processed, total) =>\n          process.send?.({\n            type: 'progress',\n            payload: { filePath, processed, total },\n          }),\n      });\n\n      // Report success to the parent.\n      process.send?.({\n        type: 'result',\n        payload: { ok: true, filePath },\n      });\n    } catch (err) {\n      // Log locally and report failure upstream; exit the worker with error code.\n      const message = extractErrorMessage(err);\n      logger.error(`[w${workerId}] ERROR ${filePath}: ${message}`);\n      process.send?.({\n        type: 'result',\n        payload: { ok: false, filePath, error: message },\n      });\n    }\n  });\n\n  // keep alive\n  await new Promise<never>(() => {\n    // This promise never resolves, keeping the worker alive indefinitely\n    // until the parent process instructs shutdown.\n  });\n}\n\nif (process.argv.includes(CHILD_FLAG)) {\n  runChild().catch((err) => {\n    logger.error(err);\n    process.exit(1);\n  });\n}\n"],"mappings":"gJAkEA,eAAsB,GAA0B,CAC9C,IAAM,EAAW,OAAO,QAAQ,IAAI,WAAa,IAAI,CACrD,EAAO,KAAK,KAAK,EAAS,cAAc,QAAQ,MAAM,CAGtD,QAAQ,OAAO,CAAE,KAAM,QAAS,CAAC,CAGjC,QAAQ,GAAG,UAAW,KAAO,IAA6B,CASxD,GARI,CAAC,GAAO,OAAO,GAAQ,WAGvB,EAAI,OAAS,YACf,QAAQ,KAAK,EAAE,CAIb,EAAI,OAAS,QAAQ,OAEzB,GAAM,CAAE,WAAU,WAAY,EAAI,QAC5B,CAAE,YAAW,iBAAgB,eAAgB,EAEnD,GAAI,CAEF,MAAM,EAAgB,CACpB,WACA,YACA,iBACA,cACA,SACA,YAAa,EAAW,IACtB,QAAQ,OAAO,CACb,KAAM,WACN,QAAS,CAAE,WAAU,YAAW,QAAO,CACxC,CAAC,CACL,CAAC,CAGF,QAAQ,OAAO,CACb,KAAM,SACN,QAAS,CAAE,GAAI,GAAM,WAAU,CAChC,CAAC,OACK,EAAK,CAEZ,IAAM,EAAU,EAAoB,EAAI,CACxC,EAAO,MAAM,KAAK,EAAS,UAAU,EAAS,IAAI,IAAU,CAC5D,QAAQ,OAAO,CACb,KAAM,SACN,QAAS,CAAE,GAAI,GAAO,WAAU,MAAO,EAAS,CACjD,CAAC,GAEJ,CAGF,MAAM,IAAI,YAAqB,GAG7B,CAGA,QAAQ,KAAK,SAAS,EAAW,EACnC,GAAU,CAAC,MAAO,GAAQ,CACxB,EAAO,MAAM,EAAI,CACjB,QAAQ,KAAK,EAAE,EACf"}