From 4a2ddf02b0749253c037ce52dcb729d69878ca56 Mon Sep 17 00:00:00 2001 From: JackBlackLight Date: Thu, 31 Oct 2024 11:11:52 -0400 Subject: [PATCH] achydra-950: monthly cron to delete stale pending works (#289) --- config/schedule.rb | 5 ++ lib/tasks/ac.rake | 34 +++++++++++ lib/tasks/resque.rake | 3 +- spec/factories/deposit.rb | 6 ++ spec/factories/user.rb | 2 +- spec/features/upload_spec.rb | 2 +- spec/tasks/ac/pending_works_spec.rb | 92 +++++++++++++++++++++++++++++ 7 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 spec/tasks/ac/pending_works_spec.rb diff --git a/config/schedule.rb b/config/schedule.rb index 933c2e412..1c5a0cc3f 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -32,3 +32,8 @@ every :day, at: '12am' do rake 'resque:restart_workers', email_subject: 'Resque workers restart' end + +# Delete stale pending works once a month +every :month do + rake 'ac:delete_stale_pending_works', email_subject: 'Delete stale pending works' +end diff --git a/lib/tasks/ac.rake b/lib/tasks/ac.rake index 12d6a1d2a..c5a3cf56b 100644 --- a/lib/tasks/ac.rake +++ b/lib/tasks/ac.rake @@ -44,4 +44,38 @@ namespace :ac do puts Rainbow('Incorrect arguments. Pass output=/path/to/file').red end end + + task delete_stale_pending_works: :environment do + log = Rails.logger + users = User.all + users.each do |current_user| + deposits = current_user.deposits.where('created_at < ?', 6.months.ago) + identifiers = deposits.map(&:hyacinth_identifier).compact + if identifiers.present? + results = AcademicCommons.search do |params| + identifiers = identifiers.map { |i| "\"#{i}\"" }.join(' OR ') + .prepend('(').concat(')') + params.filter('fedora3_pid_ssi', identifiers) + params.aggregators_only + params.field_list('fedora3_pid_ssi') + end + + hyacinth_ids_in_ac = results.documents.map { |d| d[:fedora3_pid_ssi] } + else + hyacinth_ids_in_ac = [] + end + + pending_works = deposits.to_a.keep_if do |deposit| + hyacinth_id = deposit.hyacinth_identifier + hyacinth_id.blank? || !hyacinth_ids_in_ac.include?(hyacinth_id) + end + + log.info "===Deleting #{pending_works.count} stale pending work(s)===" unless pending_works.empty? + + pending_works.each do |pending_work| + log.info pending_work.inspect + pending_work.destroy + end + end + end end diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake index ab907e2f7..296fb85be 100644 --- a/lib/tasks/resque.rake +++ b/lib/tasks/resque.rake @@ -102,8 +102,7 @@ namespace :resque do count.times do |index| number = index + 1 pidfile = Rails.root.join('tmp/pids/', "resque_work_#{number}.pid").to_s - _stdout_str, _stderr_str, status = Open3.capture3("RAILS_ENV=#{rails_env} QUEUE=\"#{queues}\" PIDFILE=#{pidfile} BACKGROUND=yes VERBOSE=1 INTERVAL=#{interval} rake resque:work >> #{out} 2>> #{err}") - puts "Worker #{number} started, status: #{status}" + Open3.capture3("RAILS_ENV=#{rails_env} QUEUE=\"#{queues}\" PIDFILE=#{pidfile} BACKGROUND=yes VERBOSE=1 INTERVAL=#{interval} rake resque:work >> #{out} 2>> #{err}") end end end diff --git a/spec/factories/deposit.rb b/spec/factories/deposit.rb index 5691344f4..bc7df846c 100644 --- a/spec/factories/deposit.rb +++ b/spec/factories/deposit.rb @@ -15,6 +15,8 @@ license { 'https://creativecommons.org/licenses/by/4.0/' } previously_published { true } current_student { false } + created_at { Time.zone.now } + hyacinth_identifier {} after(:build) do |deposit| deposit.files.attach( @@ -22,5 +24,9 @@ filename: 'test_file.txt' ) end + + trait :with_user do + association :user, factory: :user + end end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 08690065e..c08c220d2 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -3,7 +3,7 @@ uid { 'tu123' } first_name { 'Test' } last_name { 'User' } - email { 'tu123@columbia.edu' } + sequence(:email) { |n| "tu123#{n}@columbia.edu" } end factory :admin, class: User do diff --git a/spec/features/upload_spec.rb b/spec/features/upload_spec.rb index cec43986f..af9eb53b8 100644 --- a/spec/features/upload_spec.rb +++ b/spec/features/upload_spec.rb @@ -140,7 +140,7 @@ it 'sends student reminder email' do email = ActionMailer::Base.deliveries.pop expect(email.subject).to eql 'Department approval may be needed' - expect(email.to).to include 'tu123@columbia.edu' + expect(email.to).to include User.first.email end end diff --git a/spec/tasks/ac/pending_works_spec.rb b/spec/tasks/ac/pending_works_spec.rb new file mode 100644 index 000000000..c26e675ee --- /dev/null +++ b/spec/tasks/ac/pending_works_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'rake ac:delete_stale_pending_works', type: :task do + context 'when a deposit with no hyacinth identifier' do + let!(:deposit_fresh) { FactoryBot.create(:deposit, :with_user) } + let!(:deposit_stale) do + FactoryBot.create(:deposit, :with_user, created_at: 7.months.ago) + end + + describe 'that is less than 6 months old' do + it 'does not delete the deposit' do + task.execute + expect(Deposit.exists?(deposit_fresh.id)).to be true + end + end + + describe 'that is over 6 months old' do + it 'deletes the deposit' do + task.execute + expect { deposit_stale.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + context 'when a deposit with an identifier that is unindexed' do + let(:empty_response) { wrap_solr_response_data('response' => { 'docs' => [] }) } + let!(:deposit_fresh) do + FactoryBot.create(:deposit, :with_user, hyacinth_identifier: 'unindexed') + end + let!(:deposit_stale) do + FactoryBot.create(:deposit, :with_user, created_at: 7.months.ago, hyacinth_identifier: 'unindexed') + end + + before do + allow(AcademicCommons).to receive(:search).and_return(empty_response) + end + + describe 'and is less than 6 months old' do + it 'does not delete the deposit' do + task.execute + expect(Deposit.exists?(deposit_fresh.id)).to be true + end + end + + describe 'and is over 6 months old' do + it 'deletes the deposit' do + task.execute + expect { deposit_stale.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + context 'when a deposit with an identifier that is indexed' do + let(:solr_response) do + wrap_solr_response_data( + 'response' => { + 'docs' => [ + { 'id' => '10.7916/TESTDOC10', 'title_ssi' => 'First Test Document', 'object_state_ssi' => 'A', + 'cul_doi_ssi' => '10.7916/TESTDOC10', 'fedora3_pid_ssi' => 'actest:10', 'genre_ssim' => '', + 'publisher_doi_ssi' => '', 'free_to_read_start_date_ssi' => Date.current.tomorrow.strftime('%Y-%m-%d') } + ] + } + ) + end + let!(:deposit_fresh) do + FactoryBot.create(:deposit, :with_user, hyacinth_identifier: 'actest:10') + end + let!(:deposit_stale) do + FactoryBot.create(:deposit, :with_user, created_at: 7.months.ago, hyacinth_identifier: 'actest:10') + end + + before do + allow(AcademicCommons).to receive(:search).and_return(solr_response) + end + + describe 'and is less than 6 months old' do + it 'does not delete the deposit' do + task.execute + expect(Deposit.exists?(deposit_fresh.id)).to be true + end + end + + describe 'and is over 6 months old' do + it 'does not delete the deposit' do + task.execute + expect(Deposit.exists?(deposit_stale.id)).to be true + end + end + end +end