Automating Multi‑Platform Content Publishing with a Node.js Scheduler
Automating Multi‑Platform Content Publishing with a Node.js Scheduler TL;DR: I extended the content-automation repo to generate weekly newsletters, Dev.to articles, and platform‑specific markdown in a single CI run. The key was a tiny Node.js scheduler that reads a JSON manifest, writes files, and flips “generated” flags in metadata.json so downstream pipelines know what to publish. The Problem Our content pipeline had three independent manual steps: Write a weekly newsletter markdown file. Draft a Medium article. Publish a Dev.to post. Each step required copying the same body copy into a different folder ( weekly/ , content-automation/medium_* , content-automation/substack_* ) and then manually toggling flags in metadata.json . During a production run on 2026‑08‑08 the CI job failed with a cryptic log line: Error: Conn The truncated message was coming from the Prisma client that our automation script uses to fetch the latest draft from the CMS. Because the script never updated the metadata.json flags after a successful write, the next run tried to re‑process the same draft, hit a stale DB connection, and blew up. In short: the automation was not idempotent , and the state tracking was brittle. What I Tried First My first attempt was to wrap the whole generation flow in a try / catch and, on any error, abort the job without touching the manifest. I added a quick if (fs.existsSync(filePath)) return; guard to each write operation. // naive guard if ( fs . existsSync ( targetPath )) { console . log ( ` ${ targetPath } already exists – skipping` ); return ; } That prevented duplicate files, but it also silently skipped a legitimate update when we intentionally rewrote a newsletter (e.g., after a typo fix). Moreover, the guard didn’t address the stale Prisma connection, so the same Error: Conn kept surfacing in later runs. The Implementation 1. Central Manifest ( metadata.json ) The manifest now lives at content/2026/08/08/content-automation/metadata.json . I added expli