pipelineJobs.js: - cancelJob(jobId): marks job as cancelled=true, status=cancelling - isJobCancelled(jobId): checked by the pipeline between stages runSourcePipeline.js: - PipelineCancelledError class - checkCancelled() called before each of the 6 pipeline stages - Accepts options.isCancelled() callback from the job runner runKytPipelineJob.js: - Passes isCancelled: () => isJobCancelled(job.id) into pipeline - Catches PipelineCancelledError separately, sets status=cancelled routes/pipeline.js: - POST /pipeline/cancel/:jobId — marks job for cancellation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
2.1 KiB
JavaScript
77 lines
2.1 KiB
JavaScript
const express = require("express");
|
|
const { createJob, updateJob, getJob, listJobs, canStartJob, cancelJob } = require("../src/pipelineJobs");
|
|
const { runKytPipelineJob } = require("../src/runKytPipelineJob");
|
|
const { getToken } = require("../tokenStore");
|
|
const { getSource, listSources } = require("../src/business-logic/import-pipeline/sources");
|
|
|
|
const router = express.Router();
|
|
|
|
router.post("/run", async (req, res) => {
|
|
const { shop, limit = null, source = "kyt" } = req.body || {};
|
|
|
|
if (!shop) {
|
|
return res.status(400).json({ error: "Missing shop." });
|
|
}
|
|
|
|
let sourceConfig;
|
|
try {
|
|
sourceConfig = getSource(source);
|
|
} catch (error) {
|
|
return res.status(400).json({ error: error.message });
|
|
}
|
|
|
|
if (!getToken(shop)) {
|
|
return res.status(400).json({ error: "No stored Shopify token found for this shop. Complete app auth first." });
|
|
}
|
|
|
|
if (!canStartJob(shop, sourceConfig.sourceKey)) {
|
|
return res.status(409).json({ error: `An import job is already running for ${shop} and source ${sourceConfig.sourceKey}.` });
|
|
}
|
|
|
|
const job = createJob({ shop, limit, source: sourceConfig.sourceKey });
|
|
updateJob(job.id, {
|
|
status: "queued",
|
|
step: "queued",
|
|
detail: `${sourceConfig.label} import job queued`,
|
|
});
|
|
|
|
setImmediate(() => {
|
|
runKytPipelineJob(job);
|
|
});
|
|
|
|
return res.json({
|
|
jobId: job.id,
|
|
status: "queued",
|
|
shop,
|
|
source: sourceConfig.sourceKey,
|
|
limit,
|
|
});
|
|
});
|
|
|
|
router.get("/sources", (req, res) => {
|
|
return res.json({ sources: listSources() });
|
|
});
|
|
|
|
router.get("/status/:jobId", (req, res) => {
|
|
const job = getJob(req.params.jobId);
|
|
if (!job) {
|
|
return res.status(404).json({ error: "Job not found." });
|
|
}
|
|
|
|
return res.json(job);
|
|
});
|
|
|
|
router.get("/jobs", (req, res) => {
|
|
return res.json({ jobs: listJobs() });
|
|
});
|
|
|
|
router.post("/cancel/:jobId", (req, res) => {
|
|
const job = cancelJob(req.params.jobId);
|
|
if (!job) {
|
|
return res.status(404).json({ error: "Job not found or already finished." });
|
|
}
|
|
return res.json({ ok: true, jobId: job.id, status: job.status });
|
|
});
|
|
|
|
module.exports = router;
|