CMG-1093 | Contentful migration got stuck some time - #1122
CMG-1093 | Contentful migration got stuck some time#1122chetan-contentstack wants to merge 1 commit into
Conversation
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
✅ BUILD PASSED - All security checks passed |
umesh-more-cstk
left a comment
There was a problem hiding this comment.
COMMENT review - non-gating. The human decides the merge gate.
Verdict: clean, correct bug fix. I traced the root cause and both changes and they hold up.
Verified-good
writeOneFile(line 338): the old callback-basedfs.writeFilewas fire-and-forget, soawait writeOneFile(...)resolved before the bytes hit disk.migration.service.tsawaitscreateAssetsand then immediately runscreateEntry(lines 523 -> 535, and 948), and the entries step readsassets.jsonto resolve asset references - a write/read race that matches the reported "stuck / partial state" symptom. Switching toawait fs.promises.writeFilefixes it.writeOneFileis module-private (not exported), and all three call sites - 361 insidewriteFile's try/catch, and 800 & 814 insidecreateAssets' try/catch - already handle a rejection, so the now-throwing behavior introduces no unhandled rejection.mkdir(assetsSave, { recursive: true })(line 797): necessary and correctly placed. Lines 800 & 814 write viawriteOneFiledirectly, which does NOT mkdir (unlike thewriteFilehelper at line 355 used on line 816).assetsSaveis otherwise only created as a side effect of a successful per-asset write (saveAsset, line 722, on thefiles/<id>subdir). If every asset fails or throws before any success,assetsSavewould not exist and the two directwriteOneFilewrites would ENOENT - exactly what this guards.
Non-blocking
- question - error swallowing after the fix: see inline on line 800.
- nit - no automated test accompanies an IO-ordering fix (author acknowledged this in the checklist). Given the race nature, a test asserting
assets.jsonexists oncecreateAssetsresolves would lock in the fix and prevent regression.
Scope: diff is a single file in api, matching the stated Affected Area and the ticket. No unrelated churn.
| console.error("Error writing file: 3", err); | ||
| } | ||
| }); | ||
| await fs.promises.writeFile(indexPath, JSON.stringify(fileMeta)); |
There was a problem hiding this comment.
nit: Correct fix - verified. One intentional behavior change worth flagging for the record: writeOneFile now rejects on a write error instead of logging Error writing file: 3 and swallowing it. I checked all three callers (line 361 inside writeFile's try/catch, lines 800 and 814 inside createAssets' try/catch) and they all handle the rejection, so no unhandled promise rejection is introduced. No encoding arg is needed - fs.promises.writeFile defaults to utf8 for a string payload.
| await fs.promises.mkdir(assetsSave, { recursive: true }); | ||
| const assetMasterFolderPath = path.join(assetsSave, ASSETS_FAILED_FILE); | ||
|
|
||
| await writeOneFile(path.join(assetsSave, ASSETS_SCHEMA_FILE), assetData); |
There was a problem hiding this comment.
question: With writeOneFile now rejecting on failure, a failed schema write here (or the index.json/failed-assets writes at 814/816) unwinds to the createAssets catch at ~line 825, which only logs via customLogger and does NOT re-throw. migration.service.ts then proceeds from await createAssets(...) (lines 523/948) straight into createEntry, which reads assets.json. readFile (line 322) returns undefined on a missing file rather than hanging, so the entries step likely degrades to broken references rather than a hard stall - but since this ticket is specifically about migrations getting stuck, can you confirm the entries step tolerates a missing/partial assets.json gracefully? If a write genuinely fails, silently continuing may just move the failure downstream; consider surfacing it (or marking the step failed) rather than log-and-continue.
🔗 Jira Ticket
CMG-1093 — Delta migration | v1.0.0 | Contentful migration got stuck some time
📋 PR Type
📝 Description
What changed?
writeOneFilenow usesfs.promises.writeFileand is properly awaited. It was previously calling the callback-basedfs.writeFilein a fire-and-forget pattern, so the outerawait writeOneFile(...)returned before the file was actually written to disk.createAssets, addedfs.promises.mkdir(assetsSave, { recursive: true })before writing the assets schema/failed files, so the destination directory is guaranteed to exist.Why?
During delta Contentful migrations the process would occasionally hang or leave a partial state. Root cause: the assets step kicked off a non-awaited write and moved on, and if the
assetsSavedirectory did not yet exist the callback error was swallowed viaconsole.error, leaving downstream steps waiting on a file that was never written. Both issues are fixed here.🧩 Affected Areas
api— Node.js backendui— React frontendupload-api— Upload API serverdocker/docker-compose🧪 How to Test
assets/output directory as the assets step runs.assets/<project>/assets.json(and the failed-assets file, if any) are written before the next step begins.Expected result: Migration completes end-to-end; the assets directory is created if missing,
assets.jsonis fully written before subsequent steps run, and noError writing file: 3messages appear in logs.📸 Screenshots / Recordings
N/A — backend-only fix, no UI changes.
🔗 Related PRs / Dependencies
✅ Author Checklist
bugfix/cmg-1093-contentful-migration-issue.env/example.envupdated if new environment variables were added — N/Anpm test)README.md/ docs updated if behaviour changed — N/A👀 Reviewer Notes
Please focus on:
writeOneFilechange — confirm no other caller relies on the previous non-awaiting behaviour (grepshows all call sites alreadyawaitit).mkdirplacement increateAssets— it runs afterPromise.all(tasks)and before the firstwriteOneFilein that block, so both the schema file and the failed-assets file land in an existing directory.