Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from delayed job to solid queue #294

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ gem 'github_api'
gem 'sentry-rails'
gem 'sentry-ruby'

# Use delayed job for executing jobs in the background
gem 'delayed_job_active_record'
# Use solid queue for executing jobs in the background
gem 'solid_queue'

# Set CORS headers
gem 'rack-cors'
Expand Down
20 changes: 14 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,12 @@ GEM
debug (1.9.2)
irb (~> 1.10)
reline (>= 0.3.8)
delayed_job (4.1.12)
activesupport (>= 3.0, < 8.0)
delayed_job_active_record (4.1.10)
activerecord (>= 3.0, < 8.0)
delayed_job (>= 3.0, < 5)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
drb (2.2.1)
erubi (1.13.0)
et-orbi (1.2.11)
tzinfo
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
Expand All @@ -135,6 +132,9 @@ GEM
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
github_api (0.19.0)
addressable (~> 2.4)
descendants_tracker (~> 0.0.4)
Expand Down Expand Up @@ -202,6 +202,7 @@ GEM
public_suffix (5.0.4)
puma (6.4.3)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.8.1)
rack (3.1.8)
rack-cors (2.0.2)
Expand Down Expand Up @@ -285,6 +286,13 @@ GEM
sentry-ruby (5.21.0)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
solid_queue (1.0.1)
activejob (>= 7.1)
activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1)
fugit (~> 1.11.0)
railties (>= 7.1)
thor (~> 1.3.1)
sprockets (4.2.1)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
Expand Down Expand Up @@ -330,7 +338,6 @@ DEPENDENCIES
capybara
cssbundling-rails
debug
delayed_job_active_record
github_api
jbuilder
pg (~> 1.5)
Expand All @@ -343,6 +350,7 @@ DEPENDENCIES
selenium-webdriver
sentry-rails
sentry-ruby
solid_queue
sprockets-rails
tzinfo-data
unicorn (~> 6.1)
Expand Down
9 changes: 9 additions & 0 deletions app/jobs/repository_reprocess_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class RepositoryReprocessJob < ApplicationJob
queue_as :default

def perform(repository)
OrganisationMember.create_all_from_organisation(repository.organisation)
repository.pull_or_clone
repository.process_commits
end
end
13 changes: 7 additions & 6 deletions app/models/organisation_member.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ class OrganisationMember < ApplicationRecord
validates :github_name, uniqueness: { scope: :organisation }

def self.create_all_from_organisation(organisation)
OrganisationMember.where(organisation:).destroy_all
# rubocop:disable Rails/FindEach
# This is not a rails structure
Rails.application.config.github.orgs.members.all(organisation).each do |member|
OrganisationMember.create(organisation:, github_name: member['login'])
members = Rails.application.config.github.orgs.members.all(organisation)

OrganisationMember.transaction do
OrganisationMember.where(organisation:).destroy_all
members.each do |member|
OrganisationMember.create(organisation:, github_name: member['login'])
end
end
# rubocop:enable Rails/FindEach
end
end
52 changes: 23 additions & 29 deletions app/models/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Repository < ApplicationRecord
validate :not_filtered

before_create :set_path
after_save :reprocess_delayed
after_save :reprocess_in_background

def self.create_or_update_from_github_api(organisation, name, github_url, clone_url)
Repository.find_or_initialize_by(organisation:, name:) do |r|
Expand All @@ -32,34 +32,6 @@ def self.create_or_update_from_github_api(organisation, name, github_url, clone_
end.save
end

private

def set_path
self.path = Rails.root.join("repos/#{organisation.parameterize}_#{name.parameterize}")
end

def not_filtered
errors.add(:name, 'filtered') if Rails.application.config.repo_name_deny_list.include?(name)
end

def reprocess_delayed
delay.reprocess
end

def reprocess
OrganisationMember.create_all_from_organisation(organisation)
pull_or_clone
process_commits
end

def process_commits
rugged_repo.tap do |r|
walker = Rugged::Walker.new(r)
r.branches.each { |b| walker.push b.target_id }
walker.each { |c| Commit.from_rugged(c, self) }
end
end

def pull_or_clone
if Dir.exist?(path)
logger.info("Fetching #{name} and resetting to FETCH_HEAD")
Expand All @@ -72,6 +44,28 @@ def pull_or_clone
end
end

def process_commits
rugged_repo.tap do |r|
walker = Rugged::Walker.new(r)
r.branches.each { |b| walker.push b.target_id }
walker.each { |c| Commit.from_rugged(c, self) }
end
end

private

def set_path
self.path = Rails.root.join("repos/#{organisation.parameterize}_#{name.parameterize}")
end

def not_filtered
errors.add(:name, 'filtered') if Rails.application.config.repo_name_deny_list.include?(name)
end

def reprocess_in_background
RepositoryReprocessJob.perform_later(self)
end

def rugged_repo
Rugged::Repository.new(path)
end
Expand Down
5 changes: 0 additions & 5 deletions bin/delayed_job

This file was deleted.

6 changes: 6 additions & 0 deletions bin/jobs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby

require_relative "../config/environment"
require "solid_queue/cli"

SolidQueue::Cli.start(ARGV)
2 changes: 1 addition & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Application < Rails::Application
config.load_defaults 7.2
config.active_support.cache_format_version = 7.1
config.autoload_lib(ignore: %w[assets tasks])
config.active_job.queue_adapter = :delayed_job
config.active_job.queue_adapter = :solid_queue
config.organisations = %w[ZeusWPI 12urenloop]
config.repo_name_deny_list = %w[
Bestuurstaakjes
Expand Down
2 changes: 0 additions & 2 deletions config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
# Use a different cache store in production.
# config.cache_store = :mem_cache_store

# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "gamification2_production"

# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
Expand Down
1 change: 1 addition & 0 deletions config/puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

# Allow puma to be restarted by `bin/rails restart` command.
plugin :tmp_restart
plugin :solid_queue

# Only use a pidfile when requested
pidfile ENV['PIDFILE'] if ENV['PIDFILE']
18 changes: 18 additions & 0 deletions config/queue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 1
processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %>
polling_interval: 0.1

development:
<<: *default

test:
<<: *default

production:
<<: *default
10 changes: 10 additions & 0 deletions config/recurring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 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
5 changes: 5 additions & 0 deletions db/migrate/20241109090736_remove_delayed_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RemoveDelayedJob < ActiveRecord::Migration[7.2]
def change
drop_table :delayed_jobs
end
end
131 changes: 131 additions & 0 deletions db/migrate/20241109091236_add_solid_queue_tables.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
class AddSolidQueueTables < ActiveRecord::Migration[7.2]
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 %w[concurrency_key priority job_id], name: 'index_solid_queue_blocked_executions_for_release'
t.index %w[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 %w[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 %w[queue_name finished_at], name: 'index_solid_queue_jobs_for_filtering'
t.index %w[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 %w[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 %w[priority job_id], name: 'index_solid_queue_poll_all'
t.index %w[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 %w[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 %w[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 %w[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
Loading