Back to Chatwoot

Production migration guide: Rails 7.2.3.1

docs/rails_upgrades/7_2.md

4.17.05.9 KB
Original Source

Production migration guide: Rails 7.2.3.1

This checkpoint upgrades Chatwoot from Rails 7.1.5.2 to Rails 7.2.3.1. It deliberately keeps config.load_defaults 7.0, so it does not change the Rails 7.1 or 7.2 serialization, encryption, callback, job-enqueue, Active Storage WebP, or PostgreSQL date-decoding defaults.

There is no database schema migration in this checkpoint.

Application-level changes

  • The User#conversations association alias uses a Ruby method alias because Rails 7.2 reserves alias_attribute for database attributes.
  • Migration status uses ActiveRecord::MigrationContext, rather than the removed connection-level helper.
  • Strong parameters passed to Linear and LeadSquared are normalized to string-keyed hashes at their service boundaries.
  • Integration hook type assignment runs only at creation, preserving Rails 7.2 readonly-attribute behavior.
  • Existing encrypted MFA backup codes remain YAML-serialized. This release does not rewrite their persisted format.
  • devise-secure_password moves from the Chatwoot fork to upstream 2.2.1, the latest release that supports both Devise 4 and Rails 8. Later upstream releases require Devise 5.
  • Jbuilder, Debug, TestProf, and the Administrate belongs-to search field move to Rails-7.2-compatible versions.
  • Sidekiq moves to 7.3.10, which constrains connection_pool below 3. Sidekiq 7.3.1 starts workers with connection_pool 3 but crashes both scheduler threads, so this pairing is a deployment requirement rather than an optional maintenance update.
  • Rack Mini Profiler moves to 4.0.1 so development and staging profiler assets work with Rack 3.2.
  • Azure Active Storage moves from the abandoned azure-storage-blob client to the azure-blob adapter. The configured service name remains microsoft, so existing active_storage_blobs.service_name values and Azure object keys do not change.

Before deployment

  1. Take the normal PostgreSQL and Redis backups and verify the database backup can be restored.

  2. Use the same Ruby 3.4.4 and Node 24 versions as the release build.

  3. Install dependencies and build assets.

  4. Run the read-only preflight against a production replica or during the maintenance window:

    sh
    EXPECTED_RAILS_VERSION=7.2.3.1 \
    EXPECTED_CONFIG_DEFAULTS=7.0 \
    EXPECTED_SIDEKIQ_VERSION=7.3.10 \
    EXPECTED_AZURE_SERVICE=AzureBlob \
    bundle exec rails runner script/rails_upgrade/preflight.rb
    
  5. If the installation has a large number of encrypted rows, a bounded rehearsal can use PREFLIGHT_MAX_ENCRYPTED_ROWS=1000. The final production preflight should omit that limit so every encrypted value is read.

  6. If Azure is used, select a representative blob and verify that the new adapter can find it:

    sh
    ACTIVE_STORAGE_CHECK_BLOB_ID=<blob-id> \
    EXPECTED_RAILS_VERSION=7.2.3.1 \
    EXPECTED_CONFIG_DEFAULTS=7.0 \
    EXPECTED_AZURE_SERVICE=AzureBlob \
    bundle exec rails runner script/rails_upgrade/preflight.rb
    
  7. Run the explicit write/read/delete smoke against every configured storage service. This creates one uniquely named text blob and purges it in an ensure block:

    sh
    RAILS_UPGRADE_ALLOW_STORAGE_WRITE=true \
    RAILS_UPGRADE_STORAGE_SERVICE=microsoft \
    bundle exec rails runner script/rails_upgrade/active_storage_smoke.rb
    

Azure configuration

Existing shared-key installations keep the same environment variables:

  • AZURE_STORAGE_ACCOUNT_NAME
  • AZURE_STORAGE_ACCESS_KEY
  • AZURE_STORAGE_CONTAINER

The service key selected by ACTIVE_STORAGE_SERVICE remains microsoft. Only the adapter class in config/storage.yml changes from AzureStorage to AzureBlob; no blob copy or database update is required.

For an Azurite rehearsal, set AZURE_STORAGE_BLOB_HOST to the emulator endpoint and use its account name, access key, and pre-created container.

Deployment order

  1. Build the image and precompile assets before replacing any process.
  2. Run bundle exec rails db:abort_if_pending_migrations.
  3. Start one web canary and verify health, login, API authentication, Super Admin, message creation, attachments, and Action Cable.
  4. Replace the remaining web processes.
  5. Start one Sidekiq canary and verify immediate, scheduled, mail, webhook, and retry queues.
  6. Confirm startup logs show Sidekiq 7.3.10, every configured cron job is registered, and no scheduler thread reports a ConnectionPool::TimedStack#pop argument error. Wait for at least one minute-level cron job to enqueue and complete.
  7. Replace the remaining workers and scheduler.
  8. Run the full preflight again against the primary database.

Web and worker processes from the old and new release may overlap because this checkpoint retains Rails 7.0 framework defaults and does not introduce a new persisted serialization format.

Post-deployment checks

  • No increase in decrypt errors, login failures, HTTP 5xx responses, Sidekiq retries, or dead jobs.
  • Both Sidekiq scheduler threads remain alive and cron/scheduled queues continue to receive work.
  • New and existing attachments download successfully from every enabled storage backend.
  • Email ingestion and delivery, webhooks, scheduled jobs, and cron jobs continue to run.
  • Super Admin assets and custom Administrate fields render correctly.
  • Rails.version reports 7.2.3.1 and the preflight reports rails.framework_defaults as 7.0.

Rollback

Rollback is code-only because this checkpoint has no schema or data migration and keeps the old framework defaults.

  1. Restore the previous Rails 7.1 release for web and workers.
  2. Restore the previous AzureStorage adapter configuration if Azure is enabled.
  3. Re-run attachment reads, login, and a representative job.
  4. Keep the database and Redis data created during the canary; their formats remain compatible with the prior release.

Do not activate Rails 7.1/7.2 defaults in the same rollout. Encryption digest, cache/message serialization, callback ordering, job enqueue timing, WebP handling, and PostgreSQL date decoding require separately deployable compatibility work.