Keep pending delivery moving and choose how long your application retains expired authentication history.
Schedule a bounded maintenance pass
Run this command from the deployed Rails app with the same database, keys and shared cache as its web processes:
bin/rails add_auth:deliver_pendingSchedule it every minute. Each pass removes a bounded batch of expired passkey ceremonies, erases expired delivery payloads, and queues pending mail whose delivery lease is absent or expired. Enabled retention policies also delete old history. A failed phase causes the command to fail; the next pass safely repeats unfinished work.
The default batch size is 100 rows per operation and installed model, configurable from 1 to 1000. This is an initial capacity setting: measure your queue age and backlog before choosing a larger batch.
Run Solid Queue with a separate queue database
Use your host’s existing Solid Queue setup if present. Otherwise add solid_queue to its Gemfile, run bundle install, then run bin/rails generate solid_queue:install. Review the generated queue schema, worker configuration and environment changes before applying them. Follow the upstream installation instructions for your database adapter.
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = { database: { writing: :queue } }Configure the queue connection and its schema separately from the primary connection, run bin/rails db:prepare during the reviewed setup, and supervise bin/jobs start. Keep User, Session and all AddAuth authentication records together on the primary connection. AddAuth stores committed delivery intent there; the periodic sweep retries a failed queue handoff. Do not place authentication records in the queue database or depend on an outer application transaction to make a cross-database enqueue atomic.
Local acceptance covers Solid Queue 1.7.0 with a separate SQLite queue database, including rollback, queue rejection, SMTP retry and worker restart. Verify your deployment’s database adapter, shutdown procedure and mail provider. Queue choice does not determine counter choice: configure the separate atomic rate-limit store even when using Rails’ default queue and cache.
Choose a retention policy
History deletion is disabled by default. Choose retention periods for your app before serving production traffic. The following values are examples, not universal audit requirements:
AddAuth.configure do |config|
config.maintenance.batch_size = 100
config.maintenance.session_retention = 7.days
config.maintenance.email_retention = 7.days
config.maintenance.notification_retention = 30.days
end| History | When it can be deleted |
|---|---|
| Sessions | After the configured period has elapsed since expiry or revocation. Idle timeout alone does not delete a row. |
| Email token receipts | After token expiry plus email_retention. |
| Security notification receipts | After notification expiry plus notification_retention. |
Use nonnegative seconds or Rails duration helpers. nil retains that history; zero makes expired history eligible at the next sweep. Active delivery leases are protected. Credentials, account policy and live sessions are not deleted by these settings. Expired delivery secrets are erased independently of receipt retention.
Monitor progress and failure
maintenance.add_auth reports counts for a completed pass: ceremonies deleted, email/notification payloads erased, jobs enqueued and configured history deleted. A success heartbeat means a bounded pass completed; it does not mean the backlog is empty. In production, doctor reports a missing successful sweep after two minutes when passkeys, either mail feature or session retention is enabled.
bin/rails add_auth:doctorMonitor scheduler failures, oldest pending outbox age, queue depth, delivery failures and cache availability. Reaching the batch limit repeatedly warrants checking whether workers are keeping up. Repeated sweeps may enqueue duplicate jobs; worker leases and delivered-state checks handle those repeats. An ambiguous SMTP result can still duplicate the same message.
Measure backlog recovery
A local rehearsal with 5,000 live sessions and 1,200 expired sessions retained every live row and drained expired history in twelve passes at batch size 100, on both SQLite and PostgreSQL. Session listing issued two SELECTs and loaded at most 52 Session records. These are bounded-work checks, not production latency guarantees.
At one pass per minute, twelve full batches take about twelve minutes if no new work arrives and every pass completes. Measure your own arrival rate, oldest pending age and sweep duration. Alert on a failed sweep immediately, a missing heartbeat after two minutes, and pending delivery approaching the configured token expiry. Repeated full batches or rising age need operator attention even when the heartbeat is healthy. Increase batch size only after measuring database contention and worker capacity.
Recover after an interruption
- Restore the failed database, queue, mail transport or shared cache.
- Run the maintenance command and inspect its exit status and job outcomes.
- Confirm that pending age falls and a real mailbox receives an eligible message.
- Check the next scheduled pass too; a manual run does not verify recurring scheduling.
Do not log message bodies, token URLs, passwords, cookies or delivery ciphertext while diagnosing failures. Keep infrastructure logs and APM filtering aligned with Rails filtering.
Understand session pages
The session list shows the current browser first, followed by up to 50 candidates in newest-created order. Use Older sessions and Newest sessions to navigate. Activity timestamps do not reorder pages. Policy changes can shorten a page; navigation still lets the user reach older candidates. Revocation checks current account ownership and authority at the time of the action.
Next, verify the services and rollback procedure in the deployment checklist.