-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add job and task for attachment cleanup (#224)
* Add job and task for attachment cleanup * files and fixtures for tests * rake task working, tests added. * fix issues with test fixtures * trying to fix tests * purge files before object destroy * handle file deletion in batches * improve readability * fix and simplify tests
- Loading branch information
1 parent
cbc9fc2
commit f760ecc
Showing
14 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# frozen_string_literal: true | ||
|
||
# delete/destroy attachements that have been deleted X days ago | ||
class AttachmentsCleanupJob < ApplicationJob | ||
queue_as :default | ||
|
||
# Finds all deleted attachments more than `days_old`` days old, and destroys them | ||
# Params: | ||
# +days_old+:: positive integer. Number of days old and older to destroy. Default is 7 | ||
def perform(days_old = 7) | ||
if !days_old.instance_of?(Integer) || (days_old < 1) | ||
err = "'#{days_old}' is not a positive integer!" | ||
Rails.logger.error err | ||
raise err | ||
end | ||
|
||
Rails.logger.info "Cleaning up all deleted attachments which are at least #{days_old} days old." | ||
|
||
# SELECT "attachments".* FROM "attachments" | ||
# WHERE "attachments"."deleted_at" IS NOT NULL AND "attachements"."deleted_at" <= $1 | ||
attachments_to_delete = Attachment.only_deleted.where(deleted_at: ..(Date.yesterday.midnight - days_old.day)) | ||
attachments_to_delete.find_in_batches(batch_size: 50) do |group| | ||
group.each do |att| | ||
att.file.purge | ||
att.really_destroy! | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# frozen_string_literal: true | ||
|
||
namespace :attachments do | ||
desc 'destroys all attachments older than :days_old, Default = 7' | ||
task :cleanup, [:days_old] => [:environment] do |_t, args| | ||
args.with_defaults(days_old: 7) | ||
puts "Running attachment cleanup job for files deleted more than '#{args.days_old}' day ago." | ||
AttachmentsCleanupJob.perform_now(args.days_old.to_i) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@M01648:39:000000000-A2K80:1:1101:16244:1505 1:N:0:1 | ||
ATTCTAAATCACGCTGATGCAAAGAACTGATAAAACAATTGTGATTTTCTTTTAAGGCTAGATGTAAAGCACTGCCCCATTTTCCCGCACCAATAACCGCTATACGCATCAACCAAGCTTTGTTTTTAAAATTTCATTTACTTTTGCAGGATTAAAAGCTCCTTTGCCTTCTTTCATTGTTTGACCCACAAAATATCCAAAAAGTCTGTCTATACNNNTNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBAFFFFFFFGGF?AGGGGGHHHHHHG4FDGHGGGDHHHAFGHHGGHHFHHGHFFFHHHGHGHHFHFHFHFFFHGGGHHHGGGHGGGGGHEHHHHHCGCG?DGFGGGGHHHHGGEF3EGB?GGFFFCHHBGGHHHHHEGFFHHF2GGAFHEBGHHBGH2GFGF1GHHHHHHHHFBGH=FC0DDCCFGDHHH0<DH0=CDHCD00==00;0<;0###;################################ | ||
@M01648:39:000000000-A2K80:1:1101:13924:1520 1:N:0:1 | ||
TTGGGGTTTGCAAATCTATATGGAACAGAACTTGTTATCTATCTTAAATCCATCATTCCTATTGATAAAAAAGAACTTGATGATGTTTTAAGCGAGGTGGGTAATGTTATGGCTGTTGTACTTTACTCTATGGTGATTGTAGCGATATTTCAAGGTGCGCTTTTTGGTTTAATCCCAATATTTTATGGTTATGTTGGAATTTTTATGGGGGGAANNNGNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBBFFFFF5FGFGGFGGGG6E5B4GFGHHG555FFGHHFGFEGHHHFGGGFHHFHHFHFGFHBFFHHHBBEEFGFHHHHHHFFGHFHFG3F3E1EGEC1/?FGFGG4GDF3?2FHEF24??BG43BFEBBFGFHBBG3BBBGEEA</BD333F22B2///AFFF<//?<11<<1?FGB?=FGBDF11=111F1<<.1BFCFH0<<0F..--;.###.################################ | ||
@M01648:39:000000000-A2K80:1:1101:15711:1539 1:N:0:1 | ||
CAGTTATGAATACTTATTATATAGGGCTTTTAAAGAATTCTAAAAATCCAAAAGATGTAGAAGTGGGGAATTCTTTGGGTATTATTTTTCCTAATCAAGACAATAGAGGAACGCATATTAACATTAGCGGTATTGCTATGACAAAATCAAGTAAAAATCAAGATGCGGCTAAAAAATTTATGGAATTTATGTTAAGTCCTGAAATTCAATAAATTNNNANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
A3A>AFFFBFDFGGGFFFGGGGGHHACHHHHCGGHGFHHFFFAFGFFFHHGFCH2FGHHFEHHD3FEEAEHHHGFGHHGGHEFGHHHHHHHHFHHGFFBFHHHHGHHHHHFFGEEEGHHFGFGHHHFG?CEEGHHHGHHEHHHHGHFEFFHHHHHHGFBHHFDHFHCGGCFHHHHGAGFGH11DGHCGHGF>1100G0DBFB0GHH0=D0=D0<;###:################################ | ||
@M01648:39:000000000-A2K80:1:1101:15176:1589 1:N:0:1 | ||
CCCATAGGTATTTAAAGCATTTATAAGCTCCATTCTTTTTGCACTAAAATGCAGGTTAGTACTTTCTAAATCTTGTAAATATTTTGTACTTTCAAATTTTGTCATAAAACTTGATTGCATAAACACGGATAAATCTAAAACTTCACTTTTGAAATTGTCACACAAATTTTTATAATTTTTTACA | ||
+ | ||
BBBBBFFF5DFFGGGGGGFGGGHHHHHHHHHGHHHHHHHGCHHFHHGFHHGGHGHAFGHHHHHHHHHGHGHHHHHHHHGHHHFHHHHFHHHHFHEHHGHHHHHHHFBFGGHGHHHGHHHHHHHHHHGGGGGGHHHHHFBFFGHHHHHHHHHGHHHHHHDGDHHGECGHHHHHGHHHHHHHGGHG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@M01648:39:000000000-A2K80:1:1101:16244:1505 1:N:0:1 | ||
ATTCTAAATCACGCTGATGCAAAGAACTGATAAAACAATTGTGATTTTCTTTTAAGGCTAGATGTAAAGCACTGCCCCATTTTCCCGCACCAATAACCGCTATACGCATCAACCAAGCTTTGTTTTTAAAATTTCATTTACTTTTGCAGGATTAAAAGCTCCTTTGCCTTCTTTCATTGTTTGACCCACAAAATATCCAAAAAGTCTGTCTATACNNNTNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBAFFFFFFFGGF?AGGGGGHHHHHHG4FDGHGGGDHHHAFGHHGGHHFHHGHFFFHHHGHGHHFHFHFHFFFHGGGHHHGGGHGGGGGHEHHHHHCGCG?DGFGGGGHHHHGGEF3EGB?GGFFFCHHBGGHHHHHEGFFHHF2GGAFHEBGHHBGH2GFGF1GHHHHHHHHFBGH=FC0DDCCFGDHHH0<DH0=CDHCD00==00;0<;0###;################################ | ||
@M01648:39:000000000-A2K80:1:1101:13924:1520 1:N:0:1 | ||
TTGGGGTTTGCAAATCTATATGGAACAGAACTTGTTATCTATCTTAAATCCATCATTCCTATTGATAAAAAAGAACTTGATGATGTTTTAAGCGAGGTGGGTAATGTTATGGCTGTTGTACTTTACTCTATGGTGATTGTAGCGATATTTCAAGGTGCGCTTTTTGGTTTAATCCCAATATTTTATGGTTATGTTGGAATTTTTATGGGGGGAANNNGNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBBFFFFF5FGFGGFGGGG6E5B4GFGHHG555FFGHHFGFEGHHHFGGGFHHFHHFHFGFHBFFHHHBBEEFGFHHHHHHFFGHFHFG3F3E1EGEC1/?FGFGG4GDF3?2FHEF24??BG43BFEBBFGFHBBG3BBBGEEA</BD333F22B2///AFFF<//?<11<<1?FGB?=FGBDF11=111F1<<.1BFCFH0<<0F..--;.###.################################ | ||
@M01648:39:000000000-A2K80:1:1101:15711:1539 1:N:0:1 | ||
CAGTTATGAATACTTATTATATAGGGCTTTTAAAGAATTCTAAAAATCCAAAAGATGTAGAAGTGGGGAATTCTTTGGGTATTATTTTTCCTAATCAAGACAATAGAGGAACGCATATTAACATTAGCGGTATTGCTATGACAAAATCAAGTAAAAATCAAGATGCGGCTAAAAAATTTATGGAATTTATGTTAAGTCCTGAAATTCAATAAATTNNNANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
A3A>AFFFBFDFGGGFFFGGGGGHHACHHHHCGGHGFHHFFFAFGFFFHHGFCH2FGHHFEHHD3FEEAEHHHGFGHHGGHEFGHHHHHHHHFHHGFFBFHHHHGHHHHHFFGEEEGHHFGFGHHHFG?CEEGHHHGHHEHHHHGHFEFFHHHHHHGFBHHFDHFHCGGCFHHHHGAGFGH11DGHCGHGF>1100G0DBFB0GHH0=D0=D0<;###:################################ | ||
@M01648:39:000000000-A2K80:1:1101:15176:1589 1:N:0:1 | ||
GGCATAGGTATTTAAAGCATTTATAAGCTCCATTCTTTTTGCACTAAAATGCAGGTTAGTACTTTCTAAATCTTGTAAATATTTTGTACTTTCAAATTTTGTCATAAAACTTGATTGCATAAACACGGATAAATCTAAAACTTCACTTTTGAAATTGTCACACAAATTTTTATAATTTTTTACA | ||
+ | ||
BBBBBFFF5DFFGGGGGGFGGGHHHHHHHHHGHHHHHHHGCHHFHHGFHHGGHGHAFGHHHHHHHHHGHGHHHHHHHHGHHHFHHHHFHHHHFHEHHGHHHHHHHFBFGGHGHHHGHHHHHHHHHHGGGGGGHHHHHFBFFGHHHHHHHHHGHHHHHHDGDHHGECGHHHHHGHHHHHHHGGHG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@M01648:39:000000000-A2K80:1:1101:16244:1505 1:N:0:1 | ||
TTTCTAAATCACGCTGATGCAAAGAACTGATAAAACAATTGTGATTTTCTTTTAAGGCTAGATGTAAAGCACTGCCCCATTTTCCCGCACCAATAACCGCTATACGCATCAACCAAGCTTTGTTTTTAAAATTTCATTTACTTTTGCAGGATTAAAAGCTCCTTTGCCTTCTTTCATTGTTTGACCCACAAAATATCCAAAAAGTCTGTCTATACNNNTNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBAFFFFFFFGGF?AGGGGGHHHHHHG4FDGHGGGDHHHAFGHHGGHHFHHGHFFFHHHGHGHHFHFHFHFFFHGGGHHHGGGHGGGGGHEHHHHHCGCG?DGFGGGGHHHHGGEF3EGB?GGFFFCHHBGGHHHHHEGFFHHF2GGAFHEBGHHBGH2GFGF1GHHHHHHHHFBGH=FC0DDCCFGDHHH0<DH0=CDHCD00==00;0<;0###;################################ | ||
@M01648:39:000000000-A2K80:1:1101:13924:1520 1:N:0:1 | ||
AAATTTCTTTGCAAATCTATATGGAACAGAACTTGTTATCTATCTTAAATCCATCATTCCTATTGATAAAAAAGAACTTGATGATGTTTTAAGCGAGGTGGGTAATGTTATGGCTGTTGTACTTTACTCTATGGTGATTGTAGCGATATTTCAAGGTGCGCTTTTTGGTTTAATCCCAATATTTTATGGTTATGTTGGAATTTTTATGGGGGGAANNNGNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
BBBBBFFFFF5FGFGGFGGGG6E5B4GFGHHG555FFGHHFGFEGHHHFGGGFHHFHHFHFGFHBFFHHHBBEEFGFHHHHHHFFGHFHFG3F3E1EGEC1/?FGFGG4GDF3?2FHEF24??BG43BFEBBFGFHBBG3BBBGEEA</BD333F22B2///AFFF<//?<11<<1?FGB?=FGBDF11=111F1<<.1BFCFH0<<0F..--;.###.################################ | ||
@M01648:39:000000000-A2K80:1:1101:15711:1539 1:N:0:1 | ||
CAGTTATGAATACTTATTATATAGGGCTTTTAAAGAATTCTAAAAATCCAAAAGATGTAGAAGTGGGGAATTCTTTGGGTATTATTTTTCCTAATCAAGACAATAGAGGAACGCATATTAACATTAGCGGTATTGCTATGACAAAATCAAGTAAAAATCAAGATGCGGCTAAAAAATTTATGGAATTTATGTTAAGTCCTGAAATTCAATAAATTNNNANNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | ||
+ | ||
A3A>AFFFBFDFGGGFFFGGGGGHHACHHHHCGGHGFHHFFFAFGFFFHHGFCH2FGHHFEHHD3FEEAEHHHGFGHHGGHEFGHHHHHHHHFHHGFFBFHHHHGHHHHHFFGEEEGHHFGFGHHHFG?CEEGHHHGHHEHHHHGHFEFFHHHHHHGFBHHFDHFHCGGCFHHHHGAGFGH11DGHCGHGF>1100G0DBFB0GHH0=D0=D0<;###:################################ | ||
@M01648:39:000000000-A2K80:1:1101:15176:1589 1:N:0:1 | ||
GGCATAGGTATTTAAAGCATTTATAAGCTCCATTCTTTTTGCACTAAAATGCAGGTTAGTACTTTCTAAATCTTGTAAATATTTTGTACTTTCAAATTTTGTCATAAAACTTGATTGCATAAACACGGATAAATCTAAAACTTCACTTTTGAAATTGTCACACAAATTTTTATAATTTTTTACA | ||
+ | ||
BBBBBFFF5DFFGGGGGGFGGGHHHHHHHHHGHHHHHHHGCHHFHHGFHHGGHGHAFGHHHHHHHHHGHGHHHHHHHHGHHHFHHHHFHHHHFHEHHGHHHHHHHFBFGGHGHHHGHHHHHHHHHHGGGGGGHHHHHFBFFGHHHHHHHHHGHHHHHHDGDHHGECGHHHHHGHHHHHHHGGHG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'test_helper' | ||
|
||
class AttachmentsCleanupJobTest < ActiveJob::TestCase | ||
def setup | ||
@attachment1 = attachments(:attachmentA) | ||
@attachment2 = attachments(:attachmentB) | ||
@attachment3 = attachments(:attachmentC) | ||
end | ||
|
||
test 'valid attachments pretest' do | ||
assert @attachment1.valid? | ||
assert @attachment2.valid? | ||
assert @attachment3.valid? | ||
end | ||
|
||
test 'deletion after default 7 days' do | ||
# delete (soft) first attachment | ||
assert_nil @attachment1.deleted_at | ||
@attachment1.destroy | ||
assert_not_nil @attachment1.deleted_at | ||
# go forward 4 days | ||
travel 4.days | ||
# delete (soft) second attachment | ||
assert_nil @attachment2.deleted_at | ||
@attachment2.destroy | ||
assert_not_nil @attachment2.deleted_at | ||
# go forward 5 more days | ||
travel 5.days | ||
# verify files are only soft deleted | ||
assert_not_nil @attachment1.deleted_at | ||
assert_not_nil @attachment2.deleted_at | ||
assert_nil @attachment3.deleted_at | ||
|
||
# run job and verify file/object count changes | ||
assert_difference -> { ActiveStorage::Attachment.count } => -1, | ||
-> { Attachment.only_deleted.count } => -1, | ||
-> { Attachment.all.count } => 0 do | ||
AttachmentsCleanupJob.perform_now | ||
end | ||
|
||
# verify attachment exist or not | ||
id_list = Attachment.all.map(&:id) | ||
assert_not(id_list.include?(@attachment1.id)) | ||
assert_not(id_list.include?(@attachment2.id)) | ||
assert(Attachment.only_deleted.map(&:id).include?(@attachment2.id)) | ||
assert(id_list.include?(@attachment3.id)) | ||
end | ||
|
||
test 'deletion after specified 14 days' do | ||
# delete (soft) first attachment | ||
assert_nil @attachment1.deleted_at | ||
@attachment1.destroy | ||
assert_not_nil @attachment1.deleted_at | ||
# go forward 10 days | ||
travel 10.days | ||
# delete (soft) second attachment | ||
assert_nil @attachment2.deleted_at | ||
@attachment2.destroy | ||
assert_not_nil @attachment2.deleted_at | ||
# go forward 6 more days | ||
travel 6.days | ||
# verify files are only soft deleted | ||
assert_not_nil @attachment1.deleted_at | ||
assert_not_nil @attachment2.deleted_at | ||
assert_nil @attachment3.deleted_at | ||
|
||
# run job and verify file/object count changes | ||
assert_difference -> { ActiveStorage::Attachment.count } => -1, | ||
-> { Attachment.only_deleted.count } => -1, | ||
-> { Attachment.all.count } => 0 do | ||
AttachmentsCleanupJob.perform_now(14) | ||
end | ||
|
||
# verify attachment exist or not | ||
id_list = Attachment.all.map(&:id) | ||
assert_not(id_list.include?(@attachment1.id)) | ||
assert_not(id_list.include?(@attachment2.id)) | ||
assert(Attachment.only_deleted.map(&:id).include?(@attachment2.id)) | ||
assert(id_list.include?(@attachment3.id)) | ||
end | ||
|
||
test 'deletion multiple' do | ||
# delete (soft) first attachment | ||
assert_nil @attachment1.deleted_at | ||
@attachment1.destroy | ||
assert_not_nil @attachment1.deleted_at | ||
# delete (soft) second attachment | ||
assert_nil @attachment2.deleted_at | ||
@attachment2.destroy | ||
assert_not_nil @attachment2.deleted_at | ||
# go forward 9 days | ||
travel 9.days | ||
# verify files are only soft deleted | ||
assert_not_nil @attachment1.deleted_at | ||
assert_not_nil @attachment2.deleted_at | ||
assert_nil @attachment3.deleted_at | ||
|
||
# run job and verify file/object count changes | ||
assert_difference -> { ActiveStorage::Attachment.count } => -2, | ||
-> { Attachment.only_deleted.count } => -2, | ||
-> { Attachment.all.count } => 0 do | ||
AttachmentsCleanupJob.perform_now | ||
end | ||
|
||
# verify attachment exist or not | ||
id_list = Attachment.all.map(&:id) | ||
assert_not(id_list.include?(@attachment1.id)) | ||
assert_not(id_list.include?(@attachment2.id)) | ||
assert(id_list.include?(@attachment3.id)) | ||
end | ||
|
||
test 'invalid argument string' do | ||
assert_raise(Exception) do | ||
AttachmentsCleanupJob.perform_now('this is not a number') | ||
end | ||
end | ||
|
||
test 'invalid argument negative' do | ||
assert_raise(Exception) do | ||
AttachmentsCleanupJob.perform_now(-1) | ||
end | ||
end | ||
|
||
test 'invalid argument zero' do | ||
assert_raise(Exception) do | ||
AttachmentsCleanupJob.perform_now(0) | ||
end | ||
end | ||
|
||
test 'invalid argument int as string' do | ||
assert_raise(Exception) do | ||
AttachmentsCleanupJob.perform_now('1') | ||
end | ||
end | ||
end |