Skip to content

Include alembic migrations - #1584

Open
sebdiem wants to merge 3 commits into
procrastinate-org:mainfrom
sebdiem:alembic
Open

Include alembic migrations#1584
sebdiem wants to merge 3 commits into
procrastinate-org:mainfrom
sebdiem:alembic

Conversation

@sebdiem

@sebdiem sebdiem commented Jun 22, 2026

Copy link
Copy Markdown

Procrastinate ships optional Alembic revisions that wrap the same raw SQL
migration scripts already used by procrastinate schema --apply.

Independent branches via branch_labels

Each procrastinate revision module declares a revision, a down_revision
pointing to the previous procrastinate revision, and — critically —
branch_labels on the root revision:

revision = "procrastinate_0000"
down_revision = None
branch_labels = ("procrastinate",) if down_revision is None else None

This means procratinate's revision chain lives on a separate Alembic
branch
named procrastinate. A user's existing revision chain (which
also starts from down_revision = None but has no branch label) coexists
peacefully with procrastinate's branch — Alembic treats them as two
independent trees and tracks both heads in alembic_version.

No merge is required. If a user's own schema change must run after a
specific procrastinate revision, they set down_revision to that
procrastinate revision id in their own migration, exactly as they would for
any other dependency.

Resolving the versions directory

Users add procrastinate's versions to their Alembic version_locations:

[alembic]
version_locations = %(here)s/versions procrastinate:alembic/versions

The procrastinate:alembic/versions entry is resolved by Alembic from the
installed Python package, so it works regardless of where the virtualenv or
site-packages directory lives.

Minimum Alembic version

The library uses only op.get_context().autocommit_block(),
op.execute(), and version_locations all available since very early alembic.

Disclaimer

  • the code in this PR was created with the assistance of a LLM. Reviewed and tested by a human.
  • I mixed things up while submitting the PR, original submission was here

Closes #1040

Successful PR Checklist:

  • Tests
    • (not applicable?)
  • Documentation
    • (not applicable?)

PR label(s):

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional Alembic-based migration support for Procrastinate, allowing users to integrate packaged migrations into existing Alembic setups via version_locations.
  • Documentation

    • Expanded production migration guide with comprehensive Alembic integration instructions, including setup, version naming conventions, and blue-green deployment workflow examples.

sebdiem and others added 3 commits June 4, 2026 12:30
@sebdiem
sebdiem requested a review from a team as a code owner June 22, 2026 16:45
@github-actions github-actions Bot added the PR type: feature ⭐️ Contains new features label Jun 22, 2026
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds optional Alembic migration support to Procrastinate by introducing 38 Alembic revision files (procrastinate_0000procrastinate_0037) that wrap existing SQL scripts. A SchemaManager.get_alembic_versions_path() accessor exposes the versions directory. Alembic is wired as an optional dependency, integration tests verify schema equivalence, and documentation covers multi-location version trees and blue-green deployments.

Changes

Alembic migration support

Layer / File(s) Summary
Project wiring: dependencies, schema accessor, and package init
pyproject.toml, .pre-commit-config.yaml, procrastinate/schema.py, procrastinate/alembic/__init__.py, procrastinate/alembic/versions/__init__.py
Adds alembic as an optional and test dependency, pins alembic==1.18.4 and mako==1.3.12 for basedpyright, adds alembic_versions_path constant and SchemaManager.get_alembic_versions_path() static method, and adds from __future__ import annotations to both package init files.
Revision template: first file establishing the pattern
procrastinate/alembic/versions/procrastinate_0000_initial.py
Defines the full revision structure shared by all 38 files: revision metadata constants, _migration_sql() loading SQL from importlib.resources with colon-escaping, upgrade() executing inside autocommit_block, and downgrade() raising NotImplementedError.
Revision chain 0001–0037: all wrapped SQL migrations
procrastinate/alembic/versions/procrastinate_000[1-9]_*.py, procrastinate/alembic/versions/procrastinate_00[1-3][0-9]_*.py
Adds 37 additional revision modules, each chaining down_revision to the previous entry and pointing MIGRATION_FILE at the corresponding SQL script. Revisions 0029–0037 introduce pre/post naming pairs for cancel-notification, heartbeat, batch-defer-jobs, priority-lock, and retry-failed-job features.
Integration and unit tests
tests/migration/test_migration.py, tests/unit/test_schema.py, tests/conftest.py
Adds alembic_database fixture, make_alembic_config/run_alembic_migrations helpers, test_alembic_migration (runs full chain and diffs against schema_database expecting no changes), test_alembic_multiple_version_locations (verifies independent version trees), test_get_alembic_versions_path unit test, and fixes cursor_execute to return the cursor result.
Migration documentation: Alembic integration guide
docs/howto/production/migrations.md
Expands the migrations guide with procrastinate[alembic] install instructions, version_locations configuration, the procrastinate_ prefix and branch label scheme, one-SQL-script-per-revision relationship, optional down_revision ordering, and a blue-green deployment command sequence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The 38 revision files are structurally identical (low per-file reasoning cost), but the first revision's pattern, the test helpers, and the schema accessor warrant separate inspection. The bulk of the diff is highly repetitive.

Suggested reviewers

  • ewjoachim

Poem

🐇 Hop, hop, through migrations we go,
Each revision a step in the row!
alembic upgrade heads — watch it run,
Pre and post, till the schema is done.
No downgrade? No matter, we leap!
The procrastinate bunny has promises to keep. 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR fully addresses issue #1040 by implementing Alembic-based migrations, allowing users to manage Procrastinate schema changes through their existing Alembic workflow instead of manually adopting migration scripts.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing Alembic migration support. No out-of-scope modifications were introduced beyond the scope of adding Alembic revisions and supporting infrastructure.
Title check ✅ Passed The title 'Include alembic migrations' clearly and accurately summarizes the main change: adding Alembic migration support to Procrastinate. It is concise, specific, and directly reflects the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sebdiem

sebdiem commented Jun 22, 2026

Copy link
Copy Markdown
Author

sorry for the double submission I inadvertently closed the previous one

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/migration/test_migration.py (1)

217-232: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

AST-based revision extraction is correct but fragile to naming changes.

The sorted glob assumes lexicographic order matches revision order (which holds for procrastinate_NNNN naming). The AST parsing correctly extracts the revision constant. This approach works reliably for the current naming convention.

Consider adding a brief inline comment explaining why sorted-last gives the head revision, to help future maintainers:

# Files are named procrastinate_NNNN_*.py; sorted-last is the head
procrastinate_head = sorted(...)[-1]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/migration/test_migration.py` around lines 217 - 232, Add a brief inline
comment before the line with `procrastinate_head = sorted(...)[-1]` that
explains why taking the sorted-last item gives the head revision. The comment
should note that files are named with the pattern `procrastinate_NNNN_*.py`
where numeric ordering matches lexicographic ordering, making the sorted-last
approach reliable for identifying the head revision file. This helps future
maintainers understand the assumption behind this code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/migration/test_migration.py`:
- Around line 217-232: Add a brief inline comment before the line with
`procrastinate_head = sorted(...)[-1]` that explains why taking the sorted-last
item gives the head revision. The comment should note that files are named with
the pattern `procrastinate_NNNN_*.py` where numeric ordering matches
lexicographic ordering, making the sorted-last approach reliable for identifying
the head revision file. This helps future maintainers understand the assumption
behind this code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96fb5fd7-688d-4a94-9662-5168e09fc0e4

📥 Commits

Reviewing files that changed from the base of the PR and between e04023d and 2d38b4f.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (47)
  • .pre-commit-config.yaml
  • docs/howto/production/migrations.md
  • procrastinate/alembic/__init__.py
  • procrastinate/alembic/versions/__init__.py
  • procrastinate/alembic/versions/procrastinate_0000_initial.py
  • procrastinate/alembic/versions/procrastinate_0001_drop_started_at_column.py
  • procrastinate/alembic/versions/procrastinate_0002_drop_started_at_column.py
  • procrastinate/alembic/versions/procrastinate_0003_drop_procrastinate_version_table.py
  • procrastinate/alembic/versions/procrastinate_0004_fix_procrastinate_fetch_job.py
  • procrastinate/alembic/versions/procrastinate_0005_fix_trigger_status_events_insert.py
  • procrastinate/alembic/versions/procrastinate_0006_add_queueing_lock_column.py
  • procrastinate/alembic/versions/procrastinate_0007_close_fetch_job_race_condition.py
  • procrastinate/alembic/versions/procrastinate_0008_add_defer_job_function.py
  • procrastinate/alembic/versions/procrastinate_0009_add_procrastinate_periodic_defers.py
  • procrastinate/alembic/versions/procrastinate_0010_add_foreign_key_index.py
  • procrastinate/alembic/versions/procrastinate_0011_add_locks_to_periodic_defer.py
  • procrastinate/alembic/versions/procrastinate_0012_fix_procrastinate_defer_periodic_job.py
  • procrastinate/alembic/versions/procrastinate_0013_add_finish_job_and_retry_job_functions.py
  • procrastinate/alembic/versions/procrastinate_0014_add_trigger_on_job_deletion.py
  • procrastinate/alembic/versions/procrastinate_0015_delete_finished_jobs.py
  • procrastinate/alembic/versions/procrastinate_0016_add_checks_to_finish_job.py
  • procrastinate/alembic/versions/procrastinate_0017_add_checks_to_retry_job.py
  • procrastinate/alembic/versions/procrastinate_0018_fix_finish_job_compat_issue.py
  • procrastinate/alembic/versions/procrastinate_0019_add_index_on_procrastinate_jobs.py
  • procrastinate/alembic/versions/procrastinate_0020_add_kwargs_to_defer_periodic_job.py
  • procrastinate/alembic/versions/procrastinate_0021_null_locks_excluded.py
  • procrastinate/alembic/versions/procrastinate_0022_remove_old_finish_job_function.py
  • procrastinate/alembic/versions/procrastinate_0023_job_id_bigint.py
  • procrastinate/alembic/versions/procrastinate_0024_add_job_priority.py
  • procrastinate/alembic/versions/procrastinate_0025_add_periodic_job_priority.py
  • procrastinate/alembic/versions/procrastinate_0026_add_cancel_states.py
  • procrastinate/alembic/versions/procrastinate_0027_add_additional_params_to_retry_job.py
  • procrastinate/alembic/versions/procrastinate_0028_add_indexes_for_fetch_job.py
  • procrastinate/alembic/versions/procrastinate_0029_pre_cancel_notification.py
  • procrastinate/alembic/versions/procrastinate_0030_post_cancel_notification.py
  • procrastinate/alembic/versions/procrastinate_0031_pre_add_heartbeat.py
  • procrastinate/alembic/versions/procrastinate_0032_post_add_heartbeat.py
  • procrastinate/alembic/versions/procrastinate_0033_pre_batch_defer_jobs.py
  • procrastinate/alembic/versions/procrastinate_0034_post_batch_defer_jobs.py
  • procrastinate/alembic/versions/procrastinate_0035_pre_priority_lock_fetch_job.py
  • procrastinate/alembic/versions/procrastinate_0036_pre_add_retry_failed_job_procedure.py
  • procrastinate/alembic/versions/procrastinate_0037_post_add_retry_failed_job_procedure.py
  • procrastinate/schema.py
  • pyproject.toml
  • tests/conftest.py
  • tests/migration/test_migration.py
  • tests/unit/test_schema.py
✅ Files skipped from review due to trivial changes (12)
  • procrastinate/alembic/versions/procrastinate_0011_add_locks_to_periodic_defer.py
  • procrastinate/alembic/versions/procrastinate_0035_pre_priority_lock_fetch_job.py
  • procrastinate/alembic/versions/procrastinate_0028_add_indexes_for_fetch_job.py
  • procrastinate/alembic/versions/procrastinate_0007_close_fetch_job_race_condition.py
  • procrastinate/alembic/versions/procrastinate_0008_add_defer_job_function.py
  • procrastinate/alembic/init.py
  • procrastinate/alembic/versions/init.py
  • procrastinate/alembic/versions/procrastinate_0002_drop_started_at_column.py
  • tests/conftest.py
  • procrastinate/alembic/versions/procrastinate_0017_add_checks_to_retry_job.py
  • procrastinate/alembic/versions/procrastinate_0019_add_index_on_procrastinate_jobs.py
  • docs/howto/production/migrations.md

@sebdiem sebdiem changed the title Add GitHub CLI feature to devcontainer Include alembic migrations Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR type: feature ⭐️ Contains new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement a simple migration command

1 participant