diff --git a/.env.example b/.env.example index 67a45a6a..523920bb 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,4 @@ GOVUK_NOTIFY_APPLICATION_SUBMITTED_TEMPLATE_ID= AZURE_CLIENT_ID= AZURE_CLIENT_SECRET= AZURE_TENANT_ID= +REDIS_URL=redis://localhost:6379 diff --git a/.rubocop.yml b/.rubocop.yml index a02f3500..ca1c59ef 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -96,3 +96,7 @@ RSpec/VerifiedDoubles: RSpec/NestedGroups: Max: 4 + +RSpec/DescribeClass: + Exclude: + - 'spec/jobs/schedule_job_spec.rb' diff --git a/Gemfile b/Gemfile index 54400b10..3163878d 100644 --- a/Gemfile +++ b/Gemfile @@ -72,3 +72,7 @@ group :development do gem "binding_of_caller" gem "web-console" end + +gem "sidekiq", "~> 7.1" + +gem "sidekiq-cron", "~> 1.10" diff --git a/Gemfile.lock b/Gemfile.lock index d7d17e43..4b92593c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -98,6 +98,7 @@ GEM config (4.2.1) deep_merge (~> 1.2, >= 1.2.1) dry-validation (~> 1.0, >= 1.0.0) + connection_pool (2.4.1) crass (1.0.6) date (3.3.3) debug (1.8.0) @@ -150,6 +151,8 @@ GEM dry-schema (>= 1.12, < 2) zeitwerk (~> 2.6) erubi (1.12.0) + et-orbi (1.2.7) + tzinfo factory_bot (6.2.1) activesupport (>= 5.0.0) factory_bot_rails (6.2.0) @@ -162,6 +165,9 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) foreman (0.87.2) + fugit (1.8.1) + et-orbi (~> 1, >= 1.2.7) + raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) govuk-components (4.1.0) @@ -259,6 +265,7 @@ GEM public_suffix (5.0.1) puma (6.3.1) nio4r (~> 2.0) + raabro (1.4.0) racc (1.7.1) rack (2.2.8) rack-protection (3.0.6) @@ -297,6 +304,8 @@ GEM zeitwerk (~> 2.5) rainbow (3.1.1) rake (13.0.6) + redis-client (0.17.0) + connection_pool regexp_parser (2.8.1) reline (0.3.4) io-console (~> 0.5) @@ -370,6 +379,15 @@ GEM concurrent-ruby (~> 1.0, >= 1.0.2) shoulda-matchers (5.3.0) activesupport (>= 5.2.0) + sidekiq (7.1.2) + concurrent-ruby (< 2) + connection_pool (>= 2.3.0) + rack (>= 2.2.4) + redis-client (>= 0.14.0) + sidekiq-cron (1.10.1) + fugit (~> 1.8) + globalid (>= 1.0.1) + sidekiq (>= 6) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -456,6 +474,8 @@ DEPENDENCIES scenic sentry-rails (~> 5.11) shoulda-matchers (~> 5.0) + sidekiq (~> 7.1) + sidekiq-cron (~> 1.10) simplecov sprockets-rails tzinfo-data diff --git a/app/jobs/delete_stale_forms_job.rb b/app/jobs/delete_stale_forms_job.rb new file mode 100644 index 00000000..22cab5a1 --- /dev/null +++ b/app/jobs/delete_stale_forms_job.rb @@ -0,0 +1,9 @@ +class DeleteStaleFormsJob < ApplicationJob + queue_as :default + + def perform(*_args) + Form + .where("created_at < ?", 1.day.ago) + .delete_all + end +end diff --git a/config/application.rb b/config/application.rb index 41da1f6b..daa205c1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,5 +39,6 @@ class Application < Rails::Application # Don't generate system test files. config.generators.system_tests = nil + config.active_job.queue_adapter = :sidekiq end end diff --git a/config/schedule.yml b/config/schedule.yml new file mode 100644 index 00000000..0871d985 --- /dev/null +++ b/config/schedule.yml @@ -0,0 +1,3 @@ +delete_stale_forms: + cron: "0 1 * * *" + class: DeleteStaleFormsJob diff --git a/spec/jobs/delete_stale_forms_job_spec.rb b/spec/jobs/delete_stale_forms_job_spec.rb new file mode 100644 index 00000000..04cb0912 --- /dev/null +++ b/spec/jobs/delete_stale_forms_job_spec.rb @@ -0,0 +1,23 @@ +require "rails_helper" + +RSpec.describe DeleteStaleFormsJob do + subject(:job) { described_class.new } + + describe "perform" do + let(:stale_form) { build(:form, created_at: 25.hours.ago) } + let(:form) { build(:form) } + + before do + stale_form.save + form.save + end + + it { expect { job.perform }.to change(Form, :count).from(2).to(1) } + + context "delete stale forms" do + before { job.perform } + + it { expect { Form.find(id: stale_form.id) }.to raise_error(ActiveRecord::RecordNotFound) } + end + end +end diff --git a/spec/jobs/schedule_job_spec.rb b/spec/jobs/schedule_job_spec.rb new file mode 100644 index 00000000..1381e3d3 --- /dev/null +++ b/spec/jobs/schedule_job_spec.rb @@ -0,0 +1,24 @@ +require "rails_helper" + +RSpec.describe "Schedule jobs" do + subject(:schedule_jobs) { YAML.load_file(schedule_file_path) } + + let(:schedule_file_path) { "config/schedule.yml" } + + it "config file exists" do + expect(schedule_jobs).to be_present + end + + describe "DeleteStaleFormsJob" do + let(:job_name) { "delete_stale_forms" } + let(:job) { schedule_jobs[job_name] } + + it "schedule time" do + expect(job["cron"]).to eq("0 1 * * *") + end + + it "job class name" do + expect(job["class"]).to eq("DeleteStaleFormsJob") + end + end +end