1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Solid QueueをDocker環境で利用する

1
Posted at

はじめに

個人開発のアプリにて、Docker環境にてSolid Queueを利用したため備忘録として残させていただきます。

環境

  • Rails 8.10 APIモード
  • Ruby 3.3.6
Dockerfile
FROM ruby:3.3.6-alpine AS builder

RUN apk update && \
  apk add --no-cache \
  build-base \
  postgresql-dev

RUN gem install bundler
COPY Gemfile Gemfile.lock ./
ARG RAILS_ENV
RUN RAILS_ENV=${RAILS_ENV} bundle install

FROM ruby:3.3.6-alpine AS app

RUN apk update && \
  apk add --no-cache \
  tzdata \
  nodejs \
  postgresql-client \
  vim

WORKDIR /algo_sangaku_back

COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . /algo_sangaku_back

COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]
compose.yaml
compose.yaml
services:
  db:
    image: postgres:18.0-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    networks:
      - app_name-network
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - RAILS_ENV=development
    command: bundle exec puma -C config/puma.rb
    env_file:
      - .env
    volumes:
      - .:/app_name
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
      - log-data:/app_name/log
    environment:
      TZ: Asia/Tokyo
    networks:
      - app_name-network
    depends_on:
      - db

  nginx:
    build:
      context: ./nginx_docker_dev
    volumes:
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
    ports:
      - 80:80
    depends_on:
      - web
    networks:
      - app_name-network
volumes:
  public-data:

  tmp-data:
  log-data:
  db-data:

networks:
  app_name-network:
    external: true

Solid Queueのインストール

gemの追加

$ docker compose exec web bundle add solid_queue

gemを追加したためDockerコンテナのビルドを実行後に下記コマンドを実行

$ docker compose exec web rails solid_queue:install

configへの追記

solid_queue:installを実行することで追加された項目を編集します
開発環境でも利用するため、config/enviroments/development.rbにもコピーしてください

config/enviroments/production.rb
  # Replace the default in-process and non-durable queuing backend for Active Job.
  config.active_job.queue_adapter = :solid_queue
  # 単一のDBで実行するため下行はコメントアウトする
  # config.solid_queue.connects_to = { database: { writing: :queue } }

migrationの実行

solid_queue:installによってdb/queue_schema.rbが生成されますが今回は単一のDBで利用するためこれを元にmigrationファイルを作成します

migrationファイル
db/migrate/2025xxxx_solid_queue_install.rb
class SolidQueueInstall < ActiveRecord::Migration[8.1]
 def change
   create_table :solid_queue_blocked_executions do |t|
     t.bigint :job_id, null: false
     t.string :queue_name, null: false
     t.integer :priority, null: false, default: 0
     t.string :concurrency_key, null: false
     t.datetime :expires_at, null: false
     t.datetime :created_at, null: false

     t.index [ :concurrency_key, :priority, :job_id ], name: "index_solid_queue_blocked_executions_for_release"
     t.index [ :expires_at, :concurrency_key ], name: "index_solid_queue_blocked_executions_for_maintenance"
     t.index [ :job_id ], unique: true
   end

   create_table :solid_queue_claimed_executions do |t|
     t.bigint :job_id, null: false
     t.bigint :process_id
     t.datetime :created_at, null: false

     t.index [ :job_id ], unique: true
     t.index [ :process_id, :job_id ]
   end

   create_table :solid_queue_failed_executions do |t|
     t.bigint :job_id, null: false
     t.text :error
     t.datetime :created_at, null: false

     t.index [ :job_id ], unique: true
   end

   create_table :solid_queue_jobs do |t|
     t.string :queue_name, null: false
     t.string :class_name, null: false
     t.text :arguments
     t.integer :priority, null: false, default: 0
     t.string :active_job_id
     t.datetime :scheduled_at
     t.datetime :finished_at
     t.string :concurrency_key
     t.timestamps null: false

     t.index :active_job_id
     t.index :class_name
     t.index :finished_at
     t.index [ :queue_name, :finished_at ], name: "index_solid_queue_jobs_for_filtering"
     t.index [ :scheduled_at, :finished_at ], name: "index_solid_queue_jobs_for_alerting"
   end

   create_table :solid_queue_pauses do |t|
     t.string :queue_name, null: false
     t.datetime :created_at, null: false

     t.index [ :queue_name ], unique: true
   end

   create_table :solid_queue_processes do |t|
     t.string :kind, null: false
     t.datetime :last_heartbeat_at, null: false
     t.bigint :supervisor_id
     t.integer :pid, null: false
     t.string :hostname
     t.text :metadata
     t.datetime :created_at, null: false
     t.string :name, null: false

     t.index [ :last_heartbeat_at ]
     t.index [ :name, :supervisor_id ], unique: true
     t.index [ :supervisor_id ]
   end

   create_table :solid_queue_ready_executions do |t|
     t.bigint :job_id, null: false
     t.string :queue_name, null: false
     t.integer :priority, null: false, default: 0
     t.datetime :created_at, null: false

     t.index [ :job_id ], unique: true
     t.index [ :priority, :job_id ], name: "index_solid_queue_poll_all"
     t.index [ :queue_name, :priority, :job_id ], name: "index_solid_queue_poll_by_queue"
   end

   create_table :solid_queue_recurring_executions do |t|
     t.bigint :job_id, null: false
     t.string :task_key, null: false
     t.datetime :run_at, null: false
     t.datetime :created_at, null: false

     t.index [ :job_id ], unique: true
     t.index [ :task_key, :run_at ], unique: true
   end

   create_table :solid_queue_recurring_tasks do |t|
     t.string :key, null: false
     t.string :schedule, null: false
     t.string :command, limit: 2048
     t.string :class_name
     t.text :arguments
     t.string :queue_name
     t.integer :priority, default: 0
     t.boolean :static, null: false, default: true
     t.text :description
     t.timestamps null: false

     t.index [ :key ], unique: true
     t.index [ :static ]
   end

   create_table :solid_queue_scheduled_executions do |t|
     t.bigint :job_id, null: false
     t.string :queue_name, null: false
     t.integer :priority, null: false, default: 0
     t.datetime :scheduled_at, null: false
     t.datetime :created_at, null: false

     t.index [ :job_id ], unique: true
     t.index [ :scheduled_at, :priority, :job_id ], name: "index_solid_queue_dispatch_all"
   end

   create_table :solid_queue_semaphores do |t|
     t.string :key, null: false
     t.integer :value, null: false, default: 1
     t.datetime :expires_at, null: false
     t.timestamps null: false

     t.index [ :expires_at ]
     t.index [ :key, :value ]
     t.index [ :key ], unique: true
   end

   add_foreign_key :solid_queue_blocked_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
   add_foreign_key :solid_queue_claimed_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
   add_foreign_key :solid_queue_failed_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
   add_foreign_key :solid_queue_ready_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
   add_foreign_key :solid_queue_recurring_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
   add_foreign_key :solid_queue_scheduled_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade
 end
end
$ docker compose exec web rails db:migrate

キュー実行用コンテナの追加

Dokerfileはwebコンテナのものを利用
webコンテナの内容をコピーしてcommandをbin/jobsに変更

compose.yaml
services:
  db:
    image: postgres:18.0-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    networks:
      - app_name-network
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - RAILS_ENV=development
    command: bundle exec puma -C config/puma.rb
    env_file:
      - .env
    volumes:
      - .:/app_name
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
      - log-data:/app_name/log
    environment:
      TZ: Asia/Tokyo
    networks:
      - app_name-network
    depends_on:
      - db
# ここから
  queue:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - RAILS_ENV=development
    command: bin/jobs
    env_file:
      - .env
    volumes:
      - .:/app_name
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
      - log-data:/app_name/log
    environment:
      TZ: Asia/Tokyo
    networks:
      - app_name-network
    depends_on:
      - db
# ここまで
  nginx:
    build:
      context: ./nginx_docker_dev
    volumes:
      - public-data:/app_name/public
      - tmp-data:/app_name/tmp
    ports:
      - 80:80
    depends_on:
      - web
    networks:
      - app_name-network
volumes:
  public-data:

  tmp-data:
  log-data:
  db-data:

networks:
  app_name-network:
    external: true

mission_control-jobsの追加

キューの実行自体は前項までの内容で対応可能ですが、正常に実行されたかの確認及び失敗したjobの再試行を行えるようにキューの管理画面を追加します

gemの追加

$ docker compose exec web bundle add mission_control-jobs

apiモードのみpropshaftを追加

$ docker compose exec web bundle add propshaft

APIモードにて本番環境でも利用する場合はコンテナ起動のコマンドにアセットプリコンパイルコマンドを追加してください

misson_controll-jobsのマウント

config/route.rb
Rails.application.routes.draw do
  # ...
  mount MissionControl::Jobs::Engine, at: "/jobs"
  # ...
end

認証の設定

HttpBasic認証を利用するため認証情報の設定を行います

$ docker compose exec web rails mission_control:jobs:authentication:configure

credentialsに保存されるため、rails credentials:editで編集可能です

カスタム認証を利用することも可能です
https://github.com/rails/mission_control-jobs?tab=readme-ov-file#custom-authentication

上記の設定を完了することでmission_control-jobのキュー管理画面を利用することができます

localhost_jobs_applications_myapp_queues_server_id=solid_queue.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?