mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-03-25 01:14:43 +00:00
288 lines
9.2 KiB
Markdown
288 lines
9.2 KiB
Markdown
# SolidQueue, SolidCache, and SolidCable Setup
|
|
|
|
This application uses Rails 8's built-in background job processing, caching, and ActionCable features with separate dedicated databases.
|
|
|
|
## Database Configuration
|
|
|
|
We use separate databases for the main application, SolidQueue, SolidCache, and SolidCable. This ensures complete separation and avoids any conflicts or performance issues.
|
|
|
|
In `config/database.yml`, we have the following setup:
|
|
|
|
```yaml
|
|
development:
|
|
primary:
|
|
database: db/development.sqlite3
|
|
queue:
|
|
database: db/development-queue.sqlite3
|
|
cache:
|
|
database: db/development-cache.sqlite3
|
|
cable:
|
|
database: db/development-cable.sqlite3
|
|
|
|
test:
|
|
primary:
|
|
database: db/test.sqlite3
|
|
queue:
|
|
database: db/test-queue.sqlite3
|
|
cache:
|
|
database: db/test-cache.sqlite3
|
|
cable:
|
|
database: db/test-cable.sqlite3
|
|
|
|
production:
|
|
primary:
|
|
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>
|
|
queue:
|
|
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-queue
|
|
cache:
|
|
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-cache
|
|
cable:
|
|
database: <%= ENV['WRESTLINGDEV_DB_NAME'] %>-cable
|
|
```
|
|
|
|
## Migration Structure
|
|
|
|
Migrations for each database are stored in their respective directories:
|
|
|
|
- Main application migrations: `db/migrate/`
|
|
- SolidQueue migrations: `db/queue/migrate/`
|
|
- SolidCache migrations: `db/cache/migrate/`
|
|
- SolidCable migrations: `db/cable/migrate/`
|
|
|
|
## Running Migrations
|
|
|
|
When deploying the application, you need to run migrations for each database separately:
|
|
|
|
```bash
|
|
# Run main application migrations
|
|
rails db:migrate
|
|
|
|
# Run SolidQueue migrations
|
|
rails db:migrate:queue
|
|
|
|
# Run SolidCache migrations
|
|
rails db:migrate:cache
|
|
|
|
# Run SolidCable migrations
|
|
rails db:migrate:cable
|
|
```
|
|
|
|
## Environment Configuration
|
|
|
|
In the environment configuration files (`config/environments/*.rb`), we've configured the paths for migrations and set up the appropriate adapters:
|
|
|
|
```ruby
|
|
# SolidCache configuration
|
|
config.cache_store = :solid_cache_store
|
|
config.paths["db/migrate"] << "db/cache/migrate"
|
|
|
|
# SolidQueue configuration
|
|
config.active_job.queue_adapter = :solid_queue
|
|
config.paths["db/migrate"] << "db/queue/migrate"
|
|
|
|
# ActionCable configuration
|
|
config.paths["db/migrate"] << "db/cable/migrate"
|
|
```
|
|
|
|
The database connections are configured in their respective YAML files:
|
|
|
|
### config/cache.yml
|
|
```yaml
|
|
production:
|
|
database: cache
|
|
# other options...
|
|
```
|
|
|
|
### config/queue.yml
|
|
```yaml
|
|
production:
|
|
database: queue
|
|
# other options...
|
|
```
|
|
|
|
### config/cable.yml
|
|
```yaml
|
|
production:
|
|
adapter: solid_cable
|
|
database: cable
|
|
# other options...
|
|
```
|
|
|
|
## SolidQueue Configuration
|
|
|
|
SolidQueue is used for background job processing in all environments except test. The application is configured to run jobs as follows:
|
|
|
|
### Development and Production
|
|
In both development and production environments, SolidQueue is configured to process jobs asynchronously. This provides consistent behavior across environments while maintaining performance.
|
|
|
|
### Test
|
|
In the test environment only, jobs are executed synchronously using the inline adapter. This makes testing more predictable and avoids the need for separate worker processes during tests.
|
|
|
|
Configuration is in `config/initializers/solid_queue.rb`:
|
|
|
|
```ruby
|
|
# Configure ActiveJob queue adapter based on environment
|
|
if Rails.env.test?
|
|
# In test, use inline adapter for simplicity and predictability
|
|
Rails.application.config.active_job.queue_adapter = :inline
|
|
else
|
|
# In development and production, use solid_queue with async execution
|
|
Rails.application.config.active_job.queue_adapter = :solid_queue
|
|
|
|
# Configure for regular async processing
|
|
Rails.application.config.active_job.queue_adapter_options = {
|
|
execution_mode: :async,
|
|
logger: Rails.logger
|
|
}
|
|
end
|
|
```
|
|
|
|
## Running with Puma
|
|
|
|
By default, the application is configured to run SolidQueue workers within the Puma processes. This is done by setting the `SOLID_QUEUE_IN_PUMA` environment variable to `true` in the production Dockerfile, which enables the Puma plugin for SolidQueue.
|
|
|
|
This means you don't need to run separate worker processes in production - the same Puma processes that handle web requests also handle background jobs. This simplifies deployment and reduces resource requirements.
|
|
|
|
The application uses an intelligent auto-scaling configuration for SolidQueue when running in Puma:
|
|
|
|
1. **Auto Detection**: The Puma configuration automatically detects available CPU cores and memory
|
|
2. **Worker Scaling**: Puma workers are calculated based on available memory and CPU cores
|
|
3. **SolidQueue Integration**: When enabled, SolidQueue simply runs within the Puma process
|
|
|
|
You can enable SolidQueue in Puma by setting:
|
|
```bash
|
|
SOLID_QUEUE_IN_PUMA=true
|
|
```
|
|
|
|
In `config/puma.rb`:
|
|
```ruby
|
|
# Run the Solid Queue supervisor inside of Puma for single-server deployments
|
|
if ENV["SOLID_QUEUE_IN_PUMA"] == "true" && !Rails.env.test?
|
|
# Simply load the SolidQueue plugin with default settings
|
|
plugin :solid_queue
|
|
|
|
# Log that SolidQueue is enabled
|
|
puts "SolidQueue plugin enabled in Puma"
|
|
end
|
|
```
|
|
|
|
On startup, you'll see a log message confirming that SolidQueue is enabled in Puma.
|
|
|
|
## Job Owner Tracking
|
|
|
|
Jobs in this application include metadata about their owner (typically a tournament) to allow tracking and displaying job status to tournament directors. Each job includes:
|
|
|
|
- `job_owner_id`: Usually the tournament ID
|
|
- `job_owner_type`: A description of the job (e.g., "Create a backup")
|
|
|
|
This information is serialized with the job and can be used to filter and display jobs on tournament pages.
|
|
|
|
## Job Pattern: Simplified Job Enqueuing
|
|
|
|
Our job classes follow a simplified pattern that works consistently across all environments:
|
|
|
|
1. Service classes always use `perform_later` to enqueue jobs
|
|
2. The execution mode is determined centrally by the ActiveJob adapter configuration
|
|
3. Each job finds the needed records and calls the appropriate method on the service class or model
|
|
|
|
Example service class method:
|
|
```ruby
|
|
def create_backup
|
|
# Set up job owner information for tracking
|
|
job_owner_id = @tournament.id
|
|
job_owner_type = "Create a backup"
|
|
|
|
# Use perform_later which will execute based on centralized adapter config
|
|
TournamentBackupJob.perform_later(@tournament.id, @reason, job_owner_id, job_owner_type)
|
|
end
|
|
```
|
|
|
|
Example job class:
|
|
```ruby
|
|
class TournamentBackupJob < ApplicationJob
|
|
queue_as :default
|
|
|
|
# For storing job owner metadata
|
|
attr_accessor :job_owner_id, :job_owner_type
|
|
|
|
# For execution via job queue with IDs
|
|
def perform(tournament_id, reason, job_owner_id = nil, job_owner_type = nil)
|
|
# Store job owner metadata
|
|
self.job_owner_id = job_owner_id
|
|
self.job_owner_type = job_owner_type
|
|
|
|
# Find the record
|
|
tournament = Tournament.find_by(id: tournament_id)
|
|
return unless tournament
|
|
|
|
# Create the service class and call the raw method
|
|
TournamentBackupService.new(tournament, reason).create_backup_raw
|
|
end
|
|
end
|
|
```
|
|
|
|
## Job Classes
|
|
|
|
The following job classes are available:
|
|
|
|
- `AdvanceWrestlerJob`: For advancing wrestlers in brackets
|
|
- `TournamentBackupJob`: For creating tournament backups
|
|
- `WrestlingdevImportJob`: For importing from wrestlingdev
|
|
- `GenerateTournamentMatchesJob`: For generating tournament matches
|
|
- `CalculateSchoolScoreJob`: For calculating school scores
|
|
|
|
## Job Status
|
|
|
|
Jobs in this application can have the following statuses:
|
|
|
|
1. **Running**: Job is currently being executed. This is determined by checking if a record exists in the `solid_queue_claimed_executions` table for the job.
|
|
|
|
2. **Scheduled**: Job is scheduled to run at a future time. This is determined by checking if `scheduled_at` is in the future.
|
|
|
|
3. **Error**: Job has failed. This is determined by:
|
|
- Checking if a record exists in the `solid_queue_failed_executions` table for the job
|
|
- Checking if `failed_at` is present
|
|
|
|
4. **Completed**: Job has finished successfully. This is determined by checking if `finished_at` is present and no error records exist.
|
|
|
|
5. **Pending**: Job is waiting to be picked up by a worker. This is the default status when none of the above conditions are met.
|
|
|
|
## Testing Job Status
|
|
|
|
To help with testing the job status display in the UI, several rake tasks are provided:
|
|
|
|
```bash
|
|
# Create a test "Running" job for the first tournament
|
|
rails jobs:create_running
|
|
|
|
# Create a test "Completed" job for the first tournament
|
|
rails jobs:create_completed
|
|
|
|
# Create a test "Error" job for the first tournament
|
|
rails jobs:create_failed
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
If you encounter issues with SolidQueue or the separate databases:
|
|
|
|
1. Make sure all databases exist:
|
|
```sql
|
|
CREATE DATABASE IF NOT EXISTS wrestlingtourney;
|
|
CREATE DATABASE IF NOT EXISTS wrestlingtourney-queue;
|
|
CREATE DATABASE IF NOT EXISTS wrestlingtourney-cache;
|
|
CREATE DATABASE IF NOT EXISTS wrestlingtourney-cable;
|
|
```
|
|
|
|
2. Ensure all migrations have been run for each database.
|
|
|
|
3. Check that environment configurations properly connect to the right databases.
|
|
|
|
4. Verify that the database user has appropriate permissions for all databases.
|
|
|
|
5. If jobs aren't processing in production, check that `SOLID_QUEUE_IN_PUMA` is set to `true` in your environment.
|
|
|
|
## References
|
|
|
|
- [SolidQueue README](https://github.com/rails/solid_queue)
|
|
- [Rails Multiple Database Configuration](https://guides.rubyonrails.org/active_record_multiple_databases.html) |