fix(core): auto-publish scheduled content and fix SQLite datetime comparison#1216
Open
scottbuscemi wants to merge 1 commit into
Open
fix(core): auto-publish scheduled content and fix SQLite datetime comparison#1216scottbuscemi wants to merge 1 commit into
scottbuscemi wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 57f7a6c The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 57f7a6c | May 29 2026, 08:41 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 57f7a6c | May 29 2026, 08:41 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 57f7a6c | May 29 2026, 08:40 PM |
bf8f00b to
5fc2f12
Compare
…parison Two independent bugs prevented scheduled posts from ever becoming published: 1. No auto-publish mechanism existed — findReadyToPublish() was dead code, never called outside tests. Added publishScheduledContent() and wired it into middleware via after() with 15 s debounce. Uses after() to extend Worker lifetime via waitUntil on Cloudflare. Also kept as a backup in the cron system cleanup tick. 2. SQLite format mismatch (#917) — scheduled_at stores ISO 8601 with T/Z separators but datetime('now') returns space-separated format. The lexicographic comparison always returned false. Fixed by wrapping both sides in datetime() on SQLite in loader.ts, content.ts, and snapshot.ts. Verified end-to-end: scheduled posts auto-publish within 15 seconds of their scheduled time on the next request. Fixes #917
5fc2f12 to
57f7a6c
Compare
Contributor
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes scheduled posts never becoming published. Three independent bugs:
No auto-publish mechanism --
ContentRepository.findReadyToPublish()existed but was never called outside tests (dead code). The system relied on a read-time workaround inbuildStatusCondition()that treated past-due scheduled content as "effectively published" at query time, but the database status never transitioned fromscheduledtopublished.SQLite format mismatch --
scheduled_atis stored as ISO 8601 withTandZ(e.g.2026-05-05T01:41:59.000Z) but SQLite'sdatetime('now')returns2026-05-05 01:43:15. On same-day comparisons,T(0x54) > space (0x20), soscheduled_at <= datetime('now')was always false on SQLite/D1.Wrong execution path for the publish check -- The initial approach wired
publishScheduledContentinto the cron system'ssystemCleanupcallback. This failed for two reasons:NodeCronScheduleronly fires based on plugin cron tasks. With no plugins registered, the timer polls atMAX_INTERVAL_MS(5 minutes) -- far too slow for timely publishing.PiggybackSchedulerfires promises withoutwaitUntil(), so Cloudflare can kill the DB queries before they complete after the response is sent.Closes #917
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
Changes
middleware.ts-- AddedpublishScheduledContentcall directly in thedoInit()middleware path usingafter()with 15-second debounce.after()properly extends Worker lifetime viawaitUntilon Cloudflare, so the DB queries survive past the response. Capturesruntime.db(ALS-aware) before enteringafter()so playground/DO sessions get the correct database.cleanup.ts-- AddedpublishScheduledContent()that iterates all collections, finds items wherescheduled_at <= now, and publishes each viaContentRepository.publish()(revision promotion, data sync, schedule clearing, atomic per-item).emdash-runtime.ts-- Also wiredpublishScheduledContentinto the cron scheduler tick as a backup path (runs alongsiderunSystemCleanup). CalledtickCron()from middleware so the piggyback scheduler fires on Workers.loader.ts-- FixedbuildStatusCondition()to wrapscheduled_atindatetime()on SQLite, normalizing ISO 8601 T/Z format for comparison withdatetime('now').content.ts-- FixedfindReadyToPublish()to use DB-sidedatetime()comparison instead of JStoISOString()for cross-dialect correctness.snapshot.ts-- Replaced hardcodeddatetime('now')with dialect-awarecurrentTimestampValue(db)and addeddatetime()wrapping for SQLite.Verified end-to-end
Scheduled posts auto-publish within 15 seconds of their scheduled time on the next request. Tested on local Node dev server by:
scheduledtopublishedTest output
11 new tests:
publishScheduledContent: scheduled draft, published with draft changes, future dates, multiple collections, idempotency, ISO 8601 formats, error resiliencescheduled_atand SQLiteCURRENT_TIMESTAMPalways evaluates false #917 onfindReadyToPublishwith ISO 8601 T/Z formatscheduled_atand SQLiteCURRENT_TIMESTAMPalways evaluates false #917 SQLite format comparison: raw comparison proves the bug (returns false on same-day times),datetime()comparison proves the fix (returns true)Relation to PR #772
PR #772 adds an external
POST /_emdash/api/cron/publish-dueendpoint. This PR is complementary -- it makes scheduling work out of the box without requiring external cron configuration.