add pgcron + scheduling primitives to Durable#75
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 422b50a751
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| **Setup** - Enable pg_cron once at startup: | ||
|
|
||
| ```rust | ||
| use durable::setup_pgcron; |
There was a problem hiding this comment.
do we want to leave pgcron optional? we could make it mandatory later
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: README uses "PostgreSQL" instead of "Postgres"
- Updated the README line to use "Postgres" in the pg_cron integration description to match project convention.
- ✅ Fixed: Dollar-quoting breaks when content ends with tag prefix
- Adjusted
pg_literalto fall back when input ends with$durableand added a unit test covering this delimiter-boundary edge case.
- Adjusted
Or push these changes by commenting:
@cursor push 07c4b46d0a
Preview (07c4b46d0a)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -326,7 +326,7 @@
**Key behaviors:**
-- **pg_cron integration** - Schedules are backed by PostgreSQL's pg_cron extension. At each tick, pg_cron inserts a task into the queue via `durable.spawn_task()`, and workers pick it up normally.
+- **pg_cron integration** - Schedules are backed by Postgres's pg_cron extension. At each tick, pg_cron inserts a task into the queue via `durable.spawn_task()`, and workers pick it up normally.
- **Upsert semantics** - Calling `create_schedule` with an existing name updates the schedule in place.
- **Origin tracking** - Scheduled tasks automatically receive `durable::scheduled_by` and `durable::cron` headers, so tasks can identify how they were spawned.
- **Metadata filtering** - Attach arbitrary JSON metadata to schedules and filter with JSONB containment queries.
diff --git a/src/cron.rs b/src/cron.rs
--- a/src/cron.rs
+++ b/src/cron.rs
@@ -504,9 +504,10 @@
// --- SQL escaping ---
/// Dollar-quote a string using `$durable$` as the delimiter.
-/// Falls back to escaped single quotes if the content contains `$durable$`.
+/// Falls back to escaped single quotes if the content contains `$durable$`
+/// or ends with `$durable` (which would collide with the closing delimiter).
fn pg_literal(s: &str) -> String {
- if !s.contains("$durable$") {
+ if !s.contains("$durable$") && !s.ends_with("$durable") {
format!("$durable${s}$durable$")
} else {
// Fallback: single-quote escaping (double up any single quotes)
@@ -725,6 +726,12 @@
assert_eq!(pg_literal(content), "'has $durable$ and ''quotes'''");
}
+ #[test]
+ fn test_pg_literal_fallback_when_content_ends_with_delimiter_prefix() {
+ let content = "test$durable";
+ assert_eq!(pg_literal(content), "'test$durable'");
+ }
+
// --- Schedule name validation tests ---
#[test]|
|
||
| **Key behaviors:** | ||
|
|
||
| - **pg_cron integration** - Schedules are backed by PostgreSQL's pg_cron extension. At each tick, pg_cron inserts a task into the queue via `durable.spawn_task()`, and workers pick it up normally. |
There was a problem hiding this comment.
README uses "PostgreSQL" instead of "Postgres"
Low Severity
The newly added line uses "PostgreSQL's pg_cron extension" instead of the preferred "Postgres's pg_cron extension", violating the project convention to prefer "Postgres" over "PostgreSQL" in documentation.
Triggered by team rule: Prefer "Postgres" instead of PostgreSQL"
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| if s.contains("$durable") { | ||
| return Err(DurableError::InvalidConfiguration { | ||
| reason: format!( | ||
| "string contains reserved delimiter sequence '$durable': {s}" |
There was a problem hiding this comment.
Error message uses ticks instead of backticks
Low Severity
The error message in pg_literal wraps the technical term $durable with single quotes ('$durable') instead of backticks, which violates the project convention for wrapping technical terms.
Triggered by team rule: Prefer backticks (`) instead of ticks (') to wrap technical terms



Note
Medium Risk
Adds new database schema/migration and runtime integration with
pg_cron, plus queue drop behavior changes to unschedule jobs; issues here could leave orphaned jobs or break scheduling in production databases.Overview
Adds cron scheduling to
durableviapg_cron, including a new client API (setup_pgcron,create_schedule,list_schedules,delete_schedule) with validation, upsert semantics, and automatic injection ofdurable::scheduled_by/durable::cronheaders.Introduces a persistent schedule registry table
durable.cron_schedules(with metadata/task-name indexes) and updatesdurable.drop_queueto remove registered schedules and best-effort unschedule matchingpg_cronjobs. Also adds newDurableErrorvariants for cron/schedule failures, re-exports the new types inlib.rs, and expands README + integration tests covering scheduling, filtering, and error cases.Written by Cursor Bugbot for commit 5f45860. This will update automatically on new commits. Configure here.