From b80b53eb716c426bf103f72b405ca705b7ac24e0 Mon Sep 17 00:00:00 2001 From: Diego Steiner Date: Fri, 19 Jan 2024 13:35:10 +0100 Subject: [PATCH 1/3] rafactor: switch to solid_queue --- .rubocop.yml | 1 - Gemfile | 3 +- Gemfile.lock | 24 ++--- README.md | 2 +- app/jobs/mail_delivery_job.rb | 8 +- app/jobs/plan_b_backup_job.rb | 1 - app/services/health_service.rb | 22 ++-- bin/rails-worker | 2 + bin/sidekiq-job-worker | 2 - config/application.rb | 2 +- config/environments/production.rb | 6 ++ config/environments/test.rb | 2 +- config/initializers/exception_notification.rb | 2 - config/initializers/sidekiq.rb | 4 - config/solid_queue.yml | 18 ++++ ...7_create_solid_queue_tables.solid_queue.rb | 101 ++++++++++++++++++ db/schema.rb | 98 +++++++++++++++++ docker-compose.yml | 1 - 18 files changed, 248 insertions(+), 51 deletions(-) create mode 100755 bin/rails-worker delete mode 100755 bin/sidekiq-job-worker delete mode 100644 config/initializers/sidekiq.rb create mode 100644 config/solid_queue.yml create mode 100644 db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb diff --git a/.rubocop.yml b/.rubocop.yml index e6f8e156d..8155898ae 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -73,7 +73,6 @@ Style/GlobalVars: Exclude: - "app/services/cache_store_config_service.rb" - "config/initializers/redis.rb" - - "config/initializers/sidekiq.rb" Style/SymbolProc: Enabled: false diff --git a/Gemfile b/Gemfile index 76fbeb029..7f6129349 100644 --- a/Gemfile +++ b/Gemfile @@ -49,8 +49,7 @@ gem 'redis' gem 'responders' gem 'rqrcode' gem 'rubyzip' -gem 'sidekiq' -gem 'sidekiq-cron' +gem 'solid_queue' gem 'slim-rails' gem 'stackprof' gem 'statesman' diff --git a/Gemfile.lock b/Gemfile.lock index d184c3f04..50946afe9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,9 +147,6 @@ GEM country_select (10.0.1) countries (> 5.0, < 8.0) crass (1.0.6) - cronex (0.15.0) - tzinfo - unicode (>= 0.4.4.5) csv (3.3.2) database_cleaner (2.1.0) database_cleaner-active_record (>= 2, < 3) @@ -493,16 +490,6 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sidekiq (7.3.7) - connection_pool (>= 2.3.0) - logger - rack (>= 2.2.4) - redis-client (>= 0.22.2) - sidekiq-cron (2.0.1) - cronex (>= 0.13.0) - fugit (~> 1.8, >= 1.11.1) - globalid (>= 1.0.1) - sidekiq (>= 6.5.0) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -518,6 +505,13 @@ GEM actionpack (>= 3.1) railties (>= 3.1) slim (>= 3.0, < 6.0, != 5.0.0) + solid_queue (1.1.2) + activejob (>= 7.1) + activerecord (>= 7.1) + concurrent-ruby (>= 1.3.1) + fugit (~> 1.11.0) + railties (>= 7.1) + thor (~> 1.3.1) sorbet-runtime (0.5.11755) squasher (0.8.0) stackprof (0.2.26) @@ -540,7 +534,6 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unaccent (0.4.0) - unicode (0.4.4.5) unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) @@ -637,10 +630,9 @@ DEPENDENCIES ruby-lsp-rails rubyzip selenium-webdriver - sidekiq - sidekiq-cron simplecov slim-rails + solid_queue squasher stackprof statesman diff --git a/README.md b/README.md index 37f048e2e..80182dca1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Then inside the container you may run: - `bin/rails-dev-server` to start rails server - `bin/vite dev` to start vite dev server -- `bin/sidekiq-job-worker` to start the sidekiq worker process +- `bin/rails-worker` to start the active job worker process To visit the automatically created default organization, visit . diff --git a/app/jobs/mail_delivery_job.rb b/app/jobs/mail_delivery_job.rb index 01608f77d..4366de6f3 100644 --- a/app/jobs/mail_delivery_job.rb +++ b/app/jobs/mail_delivery_job.rb @@ -1,12 +1,6 @@ # frozen_string_literal: true class MailDeliveryJob < ActionMailer::MailDeliveryJob - retry_on Net::SMTPFatalError, - Net::SMTPAuthenticationError, - Net::ReadTimeout, - ActiveJob::DeserializationError, - Errno::ECONNREFUSED, + retry_on Net::SMTPFatalError, Net::SMTPAuthenticationError, Net::ReadTimeout, ActiveJob::DeserializationError, wait: 30.seconds, attempts: 5 - # discard_on ActiveJob::DeserializationError - sidekiq_options retry: 5 end diff --git a/app/jobs/plan_b_backup_job.rb b/app/jobs/plan_b_backup_job.rb index 77bbb5e06..601789c9a 100644 --- a/app/jobs/plan_b_backup_job.rb +++ b/app/jobs/plan_b_backup_job.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class PlanBBackupJob < ApplicationJob - sidekiq_options retry: 0 queue_as :default def perform(*args) diff --git a/app/services/health_service.rb b/app/services/health_service.rb index 280ad4a85..998089b83 100644 --- a/app/services/health_service.rb +++ b/app/services/health_service.rb @@ -1,20 +1,18 @@ # frozen_string_literal: true -require 'sidekiq/api' - class HealthService def cache_ok? - Rails.cache.stats.present? - rescue StandardError => e - Rails.logger.error(e) - false + # Rails.cache.stats.present? + # rescue StandardError => e + # Rails.logger.error(e) + # false end def jobs_ok? - !Sidekiq::Stats.new.queues.nil? - rescue StandardError => e - Rails.logger.error(e) - false + # !Sidekiq::Stats.new.queues.nil? + # rescue StandardError => e + # Rails.logger.error(e) + # false end def db_ok? @@ -27,8 +25,8 @@ def db_ok? def to_h { - cache: cache_ok?, - jobs: jobs_ok?, + # cache: cache_ok?, + # jobs: jobs_ok?, db: db_ok? } end diff --git a/bin/rails-worker b/bin/rails-worker new file mode 100755 index 000000000..fbba03cfb --- /dev/null +++ b/bin/rails-worker @@ -0,0 +1,2 @@ +#!/bin/sh +bundle exec rake solid_queue:start diff --git a/bin/sidekiq-job-worker b/bin/sidekiq-job-worker deleted file mode 100755 index ec56010d6..000000000 --- a/bin/sidekiq-job-worker +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -bundle exec sidekiq -q default diff --git a/config/application.rb b/config/application.rb index 2b4d5c8bd..db63f1b65 100644 --- a/config/application.rb +++ b/config/application.rb @@ -42,7 +42,7 @@ class Application < Rails::Application # Don't generate system test files. config.generators.system_tests = nil - config.active_job.queue_adapter = ENV.fetch('ACTIVE_JOB_QUEUE_ADAPTER', :inline) + config.active_job.queue_adapter = :solid_queue config.redis_config = { url: ENV.fetch('REDIS_URL', nil), ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } diff --git a/config/environments/production.rb b/config/environments/production.rb index c1082c7a9..e5b03d0e7 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -58,6 +58,12 @@ # config.active_job.queue_adapter = :resque config.cache_store = CacheStoreFactory.redis(config.redis_config) + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_name_prefix = "heimverwaltung_production" + config.active_job.queue_adapter = :solid_queue + + config.action_mailer.perform_caching = false + # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. config.action_mailer.raise_delivery_errors = true diff --git a/config/environments/test.rb b/config/environments/test.rb index 54d71d4dd..8d79afd19 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -61,5 +61,5 @@ # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true - config.active_job.queue_adapter = :inline + config.active_job.queue_adapter = :solid_queue end diff --git a/config/initializers/exception_notification.rb b/config/initializers/exception_notification.rb index 6c0b6ca1e..66db4f4eb 100644 --- a/config/initializers/exception_notification.rb +++ b/config/initializers/exception_notification.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true if defined?(ExceptionNotification) - require 'exception_notification/sidekiq' - Rails.application.config.middleware.use ExceptionNotification::Rack, email: { sender_address: ENV.fetch('MAIL_FROM', nil), diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb deleted file mode 100644 index 9a06d0d2c..000000000 --- a/config/initializers/sidekiq.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -Sidekiq.default_configuration.redis = { url: ENV.fetch('REDIS_URL', nil), - ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } diff --git a/config/solid_queue.yml b/config/solid_queue.yml new file mode 100644 index 000000000..9c1856ae5 --- /dev/null +++ b/config/solid_queue.yml @@ -0,0 +1,18 @@ +#default: &default +# dispatchers: +# - polling_interval: 1 +# batch_size: 500 +# workers: +# - queues: "*" +# threads: 5 +# processes: 1 +# polling_interval: 0.1 +# +# development: +# <<: *default +# +# test: +# <<: *default +# +# production: +# <<: *default diff --git a/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb b/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb new file mode 100644 index 000000000..6d8c4f610 --- /dev/null +++ b/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb @@ -0,0 +1,101 @@ +# This migration comes from solid_queue (originally 20231211200639) +class CreateSolidQueueTables < ActiveRecord::Migration[7.0] + def change + create_table :solid_queue_jobs do |t| + t.string :queue_name, null: false + t.string :class_name, null: false, index: true + t.text :arguments + t.integer :priority, default: 0, null: false + t.string :active_job_id, index: true + t.datetime :scheduled_at + t.datetime :finished_at, index: true + t.string :concurrency_key + + t.timestamps + + 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_scheduled_executions do |t| + t.references :job, index: { unique: true }, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + t.datetime :scheduled_at, null: false + + t.datetime :created_at, null: false + + t.index [ :scheduled_at, :priority, :job_id ], name: "index_solid_queue_dispatch_all" + end + + create_table :solid_queue_ready_executions do |t| + t.references :job, index: { unique: true }, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + + t.datetime :created_at, null: false + + 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_claimed_executions do |t| + t.references :job, index: { unique: true }, null: false + t.bigint :process_id + t.datetime :created_at, null: false + + t.index [ :process_id, :job_id ] + end + + create_table :solid_queue_blocked_executions do |t| + t.references :job, index: { unique: true }, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + t.string :concurrency_key, null: false + t.datetime :expires_at, null: false + + t.datetime :created_at, null: false + + t.index [ :expires_at, :concurrency_key ], name: "index_solid_queue_blocked_executions_for_maintenance" + end + + create_table :solid_queue_failed_executions do |t| + t.references :job, index: { unique: true }, null: false + t.text :error + t.datetime :created_at, null: false + end + + create_table :solid_queue_pauses do |t| + t.string :queue_name, null: false, index: { unique: true } + t.datetime :created_at, null: false + end + + create_table :solid_queue_processes do |t| + t.string :kind, null: false + t.datetime :last_heartbeat_at, null: false, index: true + t.bigint :supervisor_id, index: true + + t.integer :pid, null: false + t.string :hostname + t.text :metadata + + t.datetime :created_at, null: false + end + + create_table :solid_queue_semaphores do |t| + t.string :key, null: false, index: { unique: true } + t.integer :value, default: 1, null: false + t.datetime :expires_at, null: false, index: true + + t.timestamps + + t.index [ :key, :value ], name: "index_solid_queue_semaphores_on_key_and_value" + 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_scheduled_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index cdf6c4e7c..c4a32b767 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -562,6 +562,99 @@ t.index ["type"], name: "index_rich_text_templates_on_type" end + create_table "solid_queue_blocked_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.string "concurrency_key", null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance" + t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true + end + + create_table "solid_queue_claimed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.bigint "process_id" + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true + t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" + end + + create_table "solid_queue_failed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.text "error" + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true + end + + create_table "solid_queue_jobs", force: :cascade do |t| + t.string "queue_name", null: false + t.string "class_name", null: false + t.text "arguments" + t.integer "priority", default: 0, null: false + t.string "active_job_id" + t.datetime "scheduled_at" + t.datetime "finished_at" + t.string "concurrency_key" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id" + t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name" + t.index ["finished_at"], name: "index_solid_queue_jobs_on_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", force: :cascade do |t| + t.string "queue_name", null: false + t.datetime "created_at", null: false + t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true + end + + create_table "solid_queue_processes", force: :cascade 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.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id" + end + + create_table "solid_queue_ready_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_ready_executions_on_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_scheduled_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "scheduled_at", null: false + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true + t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all" + end + + create_table "solid_queue_semaphores", force: :cascade do |t| + t.string "key", null: false + t.integer "value", default: 1, null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at" + t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value" + t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true + end + create_table "tarifs", force: :cascade do |t| t.string "type" t.boolean "pin", default: true @@ -731,6 +824,11 @@ add_foreign_key "payments", "invoices" add_foreign_key "plan_b_backups", "organisations" add_foreign_key "rich_text_templates", "organisations" + 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_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "tarifs", "booking_questions", column: "prefill_usage_booking_question_id" add_foreign_key "tarifs", "organisations" add_foreign_key "tarifs", "vat_categories" diff --git a/docker-compose.yml b/docker-compose.yml index c94fe2a2e..728a7afa6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,7 +19,6 @@ services: SMTP_SETTINGS: '{ "address":"mail" }' MAIL_FROM: "no-reply@heimverwaltung.localhost" REDIS_URL: "redis://redis/0" - ACTIVE_JOB_QUEUE_ADAPTER: "sidekiq" TRANSLATION_IO_API_KEY: ${TRANSLATION_IO_API_KEY} PRIVACY_STATEMENT_URL: ${PRIVACY_STATEMENT_URL} GITHUB_URL: ${GITHUB_URL} From 4c58e13756dbba2d11f58548d3eeb3d713973fc9 Mon Sep 17 00:00:00 2001 From: Diego Steiner Date: Mon, 20 Jan 2025 15:42:58 +0000 Subject: [PATCH 2/3] chore: rebase --- Gemfile | 2 +- bin/jobs | 6 + config/environments/production.rb | 4 +- config/environments/test.rb | 2 - config/queue.yml | 18 +++ config/recurring.yml | 31 +++++ config/schedule.yml | 16 --- ...7_create_solid_queue_tables.solid_queue.rb | 101 -------------- .../20250120143650_add_solid_queue_tables.rb | 131 ++++++++++++++++++ db/schema.rb | 31 ++++- kubernetes/kustomization.yaml | 1 - kubernetes/worker-deployment.yaml | 2 +- 12 files changed, 219 insertions(+), 126 deletions(-) create mode 100755 bin/jobs create mode 100644 config/queue.yml create mode 100644 config/recurring.yml delete mode 100644 config/schedule.yml delete mode 100644 db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb create mode 100644 db/migrate/20250120143650_add_solid_queue_tables.rb diff --git a/Gemfile b/Gemfile index 7f6129349..997727afc 100644 --- a/Gemfile +++ b/Gemfile @@ -49,8 +49,8 @@ gem 'redis' gem 'responders' gem 'rqrcode' gem 'rubyzip' -gem 'solid_queue' gem 'slim-rails' +gem 'solid_queue' gem 'stackprof' gem 'statesman' gem 'store_model' diff --git a/bin/jobs b/bin/jobs new file mode 100755 index 000000000..dcf59f309 --- /dev/null +++ b/bin/jobs @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +require_relative "../config/environment" +require "solid_queue/cli" + +SolidQueue::Cli.start(ARGV) diff --git a/config/environments/production.rb b/config/environments/production.rb index e5b03d0e7..710abd67e 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -53,14 +53,12 @@ # Replace the default in-process memory cache store with a durable alternative. # config.cache_store = :mem_cache_store - - # Replace the default in-process and non-durable queuing backend for Active Job. - # config.active_job.queue_adapter = :resque config.cache_store = CacheStoreFactory.redis(config.redis_config) # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_name_prefix = "heimverwaltung_production" config.active_job.queue_adapter = :solid_queue + config.solid_queue.connects_to = { database: { writing: :queue } } config.action_mailer.perform_caching = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 8d79afd19..84aefc55b 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -60,6 +60,4 @@ # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true - - config.active_job.queue_adapter = :solid_queue end diff --git a/config/queue.yml b/config/queue.yml new file mode 100644 index 000000000..8c3050347 --- /dev/null +++ b/config/queue.yml @@ -0,0 +1,18 @@ +# default: &default +# dispatchers: +# - polling_interval: 1 +# batch_size: 500 +# workers: +# - queues: "*" +# threads: 3 +# processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %> +# polling_interval: 0.1 + +# development: +# <<: *default + +# test: +# <<: *default + +# production: +# <<: *default diff --git a/config/recurring.yml b/config/recurring.yml new file mode 100644 index 000000000..71fe26dc2 --- /dev/null +++ b/config/recurring.yml @@ -0,0 +1,31 @@ +# production: +# periodic_cleanup: +# class: CleanSoftDeletedRecordsJob +# queue: background +# args: [ 1000, { batch_size: 500 } ] +# schedule: every hour +# periodic_command: +# command: "SoftDeletedRecord.due.delete_all" +# priority: 2 +# schedule: at 5am every day + +development: + transition_booking_states: + schedule: "0 * * * *" + class: TransitionBookingStatesJob + +# test: +# <<: *default + +production: + transition_booking_states: + schedule: "*/5 * * * *" + class: TransitionBookingStatesJob + + clean_data_digests: + schedule: "0 3 * * *" + class: CleanDataDigestsJob + + schedule_plan_b_backups: + schedule: "0 2 * * *" + class: SchedulePlanBBackupsJob diff --git a/config/schedule.yml b/config/schedule.yml deleted file mode 100644 index 4bc619933..000000000 --- a/config/schedule.yml +++ /dev/null @@ -1,16 +0,0 @@ -# config/schedule.yml - -transition_booking_states: - cron: "0 * * * *" - class: TransitionBookingStatesJob - queue: default - -clean_data_digests: - cron: "0 3 * * *" - class: CleanDataDigestsJob - queue: default - -schedule_plan_b_backups: - cron: "0 2 * * *" - class: SchedulePlanBBackupsJob - queue: default diff --git a/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb b/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb deleted file mode 100644 index 6d8c4f610..000000000 --- a/db/migrate/20240119091517_create_solid_queue_tables.solid_queue.rb +++ /dev/null @@ -1,101 +0,0 @@ -# This migration comes from solid_queue (originally 20231211200639) -class CreateSolidQueueTables < ActiveRecord::Migration[7.0] - def change - create_table :solid_queue_jobs do |t| - t.string :queue_name, null: false - t.string :class_name, null: false, index: true - t.text :arguments - t.integer :priority, default: 0, null: false - t.string :active_job_id, index: true - t.datetime :scheduled_at - t.datetime :finished_at, index: true - t.string :concurrency_key - - t.timestamps - - 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_scheduled_executions do |t| - t.references :job, index: { unique: true }, null: false - t.string :queue_name, null: false - t.integer :priority, default: 0, null: false - t.datetime :scheduled_at, null: false - - t.datetime :created_at, null: false - - t.index [ :scheduled_at, :priority, :job_id ], name: "index_solid_queue_dispatch_all" - end - - create_table :solid_queue_ready_executions do |t| - t.references :job, index: { unique: true }, null: false - t.string :queue_name, null: false - t.integer :priority, default: 0, null: false - - t.datetime :created_at, null: false - - 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_claimed_executions do |t| - t.references :job, index: { unique: true }, null: false - t.bigint :process_id - t.datetime :created_at, null: false - - t.index [ :process_id, :job_id ] - end - - create_table :solid_queue_blocked_executions do |t| - t.references :job, index: { unique: true }, null: false - t.string :queue_name, null: false - t.integer :priority, default: 0, null: false - t.string :concurrency_key, null: false - t.datetime :expires_at, null: false - - t.datetime :created_at, null: false - - t.index [ :expires_at, :concurrency_key ], name: "index_solid_queue_blocked_executions_for_maintenance" - end - - create_table :solid_queue_failed_executions do |t| - t.references :job, index: { unique: true }, null: false - t.text :error - t.datetime :created_at, null: false - end - - create_table :solid_queue_pauses do |t| - t.string :queue_name, null: false, index: { unique: true } - t.datetime :created_at, null: false - end - - create_table :solid_queue_processes do |t| - t.string :kind, null: false - t.datetime :last_heartbeat_at, null: false, index: true - t.bigint :supervisor_id, index: true - - t.integer :pid, null: false - t.string :hostname - t.text :metadata - - t.datetime :created_at, null: false - end - - create_table :solid_queue_semaphores do |t| - t.string :key, null: false, index: { unique: true } - t.integer :value, default: 1, null: false - t.datetime :expires_at, null: false, index: true - - t.timestamps - - t.index [ :key, :value ], name: "index_solid_queue_semaphores_on_key_and_value" - 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_scheduled_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade - end -end diff --git a/db/migrate/20250120143650_add_solid_queue_tables.rb b/db/migrate/20250120143650_add_solid_queue_tables.rb new file mode 100644 index 000000000..f6a21ecfa --- /dev/null +++ b/db/migrate/20250120143650_add_solid_queue_tables.rb @@ -0,0 +1,131 @@ +class AddSolidQueueTables < ActiveRecord::Migration[8.0] + def change + create_table "solid_queue_blocked_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + 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" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true + end + + create_table "solid_queue_claimed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.bigint "process_id" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true + t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" + end + + create_table "solid_queue_failed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.text "error" + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true + end + + create_table "solid_queue_jobs", force: :cascade do |t| + t.string "queue_name", null: false + t.string "class_name", null: false + t.text "arguments" + t.integer "priority", default: 0, null: false + t.string "active_job_id" + t.datetime "scheduled_at" + t.datetime "finished_at" + t.string "concurrency_key" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id" + t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name" + t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_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", force: :cascade do |t| + t.string "queue_name", null: false + t.datetime "created_at", null: false + t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true + end + + create_table "solid_queue_processes", force: :cascade 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" ], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true + t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id" + end + + create_table "solid_queue_ready_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_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", force: :cascade 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" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true + t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true + end + + create_table "solid_queue_recurring_tasks", force: :cascade 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", default: true, null: false + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true + t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static" + end + + create_table "solid_queue_scheduled_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "scheduled_at", null: false + t.datetime "created_at", null: false + t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true + t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all" + end + + create_table "solid_queue_semaphores", force: :cascade do |t| + t.string "key", null: false + t.integer "value", default: 1, null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at" + t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value" + t.index [ "key" ], name: "index_solid_queue_semaphores_on_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 diff --git a/db/schema.rb b/db/schema.rb index c4a32b767..df5e723b0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_01_09_153822) do +ActiveRecord::Schema[8.0].define(version: 2025_01_20_143650) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" enable_extension "pgcrypto" @@ -569,6 +569,7 @@ 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"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true end @@ -620,7 +621,9 @@ t.string "hostname" t.text "metadata" t.datetime "created_at", null: false + t.string "name", null: false t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index ["name", "supervisor_id"], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id" end @@ -634,6 +637,31 @@ t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue" end + create_table "solid_queue_recurring_executions", force: :cascade 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"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true + t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true + end + + create_table "solid_queue_recurring_tasks", force: :cascade 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", default: true, null: false + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["key"], name: "index_solid_queue_recurring_tasks_on_key", unique: true + t.index ["static"], name: "index_solid_queue_recurring_tasks_on_static" + end + create_table "solid_queue_scheduled_executions", force: :cascade do |t| t.bigint "job_id", null: false t.string "queue_name", null: false @@ -828,6 +856,7 @@ 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 add_foreign_key "tarifs", "booking_questions", column: "prefill_usage_booking_question_id" add_foreign_key "tarifs", "organisations" diff --git a/kubernetes/kustomization.yaml b/kubernetes/kustomization.yaml index 8598cb60f..dafec44ab 100644 --- a/kubernetes/kustomization.yaml +++ b/kubernetes/kustomization.yaml @@ -44,6 +44,5 @@ configMapGenerator: - RAILS_LOG_TO_STDOUT=true - RAILS_SERVE_STATIC_FILES=true - REDIS_URL=redis://redis-service/0 - - ACTIVE_JOB_QUEUE_ADAPTER=sidekiq - MAIL_FROM= - PRIVACY_STATEMENT_URL=https://www.heimv.ch/privacy/ diff --git a/kubernetes/worker-deployment.yaml b/kubernetes/worker-deployment.yaml index ebc96d580..bfd80e0f9 100644 --- a/kubernetes/worker-deployment.yaml +++ b/kubernetes/worker-deployment.yaml @@ -21,7 +21,7 @@ spec: image: ghcr.io/diegosteiner/heimv:main imagePullPolicy: Always command: - - bin/sidekiq-job-worker + - bin/jobs envFrom: - secretRef: name: app-secret From f0f1ac5b3fc8e1dc60f3fc93ccab90c3e30bc25a Mon Sep 17 00:00:00 2001 From: Diego Steiner Date: Mon, 20 Jan 2025 16:04:17 +0000 Subject: [PATCH 3/3] fix: changes from pr --- README.md | 2 +- config/environments/production.rb | 2 +- config/environments/test.rb | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 80182dca1..c96b16391 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Then inside the container you may run: - `bin/rails-dev-server` to start rails server - `bin/vite dev` to start vite dev server -- `bin/rails-worker` to start the active job worker process +- `bin/jobs` to start the active job worker process To visit the automatically created default organization, visit . diff --git a/config/environments/production.rb b/config/environments/production.rb index 710abd67e..c3c5eef68 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -58,7 +58,7 @@ # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_name_prefix = "heimverwaltung_production" config.active_job.queue_adapter = :solid_queue - config.solid_queue.connects_to = { database: { writing: :queue } } + # config.solid_queue.connects_to = { database: { writing: :queue } } config.action_mailer.perform_caching = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 84aefc55b..54d71d4dd 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -60,4 +60,6 @@ # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true + + config.active_job.queue_adapter = :inline end