Skip to content

fix: confine all objects to the apalis schema (#86)#89

Open
tysen wants to merge 1 commit into
apalis-dev:mainfrom
tysen:fix/confine-to-apalis-schema
Open

fix: confine all objects to the apalis schema (#86)#89
tysen wants to merge 1 commit into
apalis-dev:mainfrom
tysen:fix/confine-to-apalis-schema

Conversation

@tysen
Copy link
Copy Markdown

@tysen tysen commented Jun 4, 2026

Fixes #86

Every object apalis creates now lives in the apalis schema:

  • generate_ulid() is created as apalis.generate_ulid() with a pinned SET search_path = apalis, public, so its bare gen_random_bytes() call resolves whether pgcrypto is installed into apalis (fresh DBs) or already exists in public.
  • pgcrypto is installed with SCHEMA apalis on fresh databases.
  • The sqlx migrations table moves to apalis._sqlx_migrations via a new sqlx.toml (create-schemas + table-name), which requires sqlx 0.9. The first migration's CREATE SCHEMA is now IF NOT EXISTS to coexist with create-schemas.

Also bumps sqlx 0.8 -> 0.9 and remaps the runtime/TLS cargo features (0.9 removed the combined runtime-*-tls flags), regenerates the .sqlx offline cache, and updates deny.toml / cargo-vet exemptions for the new dependency tree.

BREAKING CHANGE: existing pre-1.0 deployments track migrations in public._sqlx_migrations; after this change sqlx looks in apalis._sqlx_migrations and will try to re-run every migration. Recreate the apalis schema (and drop public._sqlx_migrations) when upgrading.

@tysen tysen requested a review from geofmureithi as a code owner June 4, 2026 17:06
@geofmureithi
Copy link
Copy Markdown
Member

geofmureithi commented Jun 4, 2026 via email

Move the objects apalis creates out of `public`

- generate_ulid() becomes apalis.generate_ulid() and no longer depends on
  pgcrypto -- its 10 random bytes come from core gen_random_uuid() instead
  of pgcrypto's gen_random_bytes(). A new forward migration creates it,
  repoints the legacy (driver-unused) apalis.push_job at it, and drops
  public.generate_ulid.
- The sqlx migrations table moves from public._sqlx_migrations to
  apalis._sqlx_migrations via a new sqlx.toml (requires sqlx 0.9). This
  also isolates apalis's migration history from a user's own sqlx
  migrations, which previously collided over the shared default table name.
- pgcrypto is no longer used; it is left where an earlier version installed
  it and documented as droppable.

The upgrade is automatic and non-breaking. PostgresStorage::setup()
relocates an existing apalis-owned public._sqlx_migrations into the apalis
schema and re-stamps checksums (read from the embedded migrator) before
running migrations, so existing deployments migrate with no manual steps
and nothing is re-run. The relocation is guarded so it never adopts a
user's own public._sqlx_migrations sharing the default name. The only
edited migration is the first one (CREATE SCHEMA -> CREATE SCHEMA IF NOT
EXISTS, so create-schemas can pre-create the schema on fresh installs);
its checksum is healed by the same transition.

Also bumps sqlx 0.8 -> 0.9 (remapping the runtime/TLS cargo features that
0.9 split apart) and updates deny.toml / cargo-vet for the new dep tree.
@tysen tysen force-pushed the fix/confine-to-apalis-schema branch from b4c57bb to 513c73b Compare June 5, 2026 19:55
Comment thread src/lib.rs
/// The move is guarded so it never adopts a `public._sqlx_migrations` that
/// belongs to a user's own sqlx migrations sharing the default name.
#[cfg(feature = "migrate")]
async fn relocate_legacy_migrations_table(pool: &PgPool) -> Result<(), sqlx::Error> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think rather than doing this, why not use sqlx migrations? I am not sure why we need to have a special function to handle this as its not an edge case. Migrating a past migration is a big no no.

@@ -1,4 +1,4 @@
CREATE SCHEMA apalis;
CREATE SCHEMA IF NOT EXISTS apalis;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You cannot directly modify migrations. This would break anyone already with this migration. Is there a specific reason you need to do this?

@tysen
Copy link
Copy Markdown
Author

tysen commented Jun 7, 2026

The accidental pollution of the public schema with generate_ulid and pgcrypto is unfortunate but mostly harmless. Creating and using _sqlx_migrations in public is a real problem that has bitten users many times (see apalis-dev/apalis#81, apalis-dev/apalis#177, apalis-dev/apalis#439, #64).

I think you have an opportunity with your impending 1.0 release to make a breaking change and clean this up - this PR does so. The 0.9 version of sqlx lets us easily configure _sqlx_migrations to live in apalis. It is fortuitous that sqlx has added this capability right around now!

We have to edit the first migration because of the missing IF NOT EXISTS - because we would be creating the apalis schema outside of (and before) the sqlx migrations, it would fail otherwise.

We can't use an sqlx migration to move _sqlx_migrations into the apalis schema because sqlx creates and reads that table at the start of Migrator::run, before any migration in the set executes — so a migration can never relocate the table that's tracking it (it would run too late, and against the freshly-created table in the new location). Instead, PostgresStorage::setup() does the one-time move, relocating an existing public._sqlx_migrations into apalis and re-stamping the one edited migration's checksum, before handing off to the migrator. I believe this will work for new and existing users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confine all objects to the apalis schema (generate_ulid, _sqlx_migrations, pgcrypto currently leak into public)

2 participants