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

Add Rake task and Resque job to delete old auto snapshots #861

Merged
merged 1 commit into from
Sep 7, 2017
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
9 changes: 9 additions & 0 deletions app/jobs/pageflow/prune_auto_snapshots_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Pageflow
class PruneAutoSnapshotsJob
@queue = :prune

def self.perform(entry_id, options)
AutoSnapshotPruning.prune(Entry.find(entry_id), options.symbolize_keys)
end
end
end
26 changes: 26 additions & 0 deletions app/models/pageflow/auto_snapshot_pruning.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Pageflow
# @api private
module AutoSnapshotPruning
extend self

def dirty_entry_ids(options)
Revision
.auto_snapshots
.where('created_at < ?', options.fetch(:created_before))
.select('COUNT(*) as revisions_count, entry_id')
.group('entry_id')
.having('revisions_count > ?', options.fetch(:keep_count))
.map(&:entry_id)
end

def prune(entry, options)
entry
.revisions
.auto_snapshots
.where('created_at < ?', options[:created_before])
.order('created_at DESC')
.offset(options[:keep_count])
.each(&:destroy)
end
end
end
2 changes: 1 addition & 1 deletion app/models/pageflow/chapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Chapter < ActiveRecord::Base
include SerializedConfiguration

belongs_to :storyline, touch: true
has_many :pages, -> { order('position ASC') }
has_many :pages, -> { order('position ASC') }, dependent: :destroy

delegate :entry, to: :storyline

Expand Down
7 changes: 5 additions & 2 deletions app/models/pageflow/revision.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ class Revision < ActiveRecord::Base
belongs_to :restored_from, :class_name => 'Pageflow::Revision'

has_many :widgets, as: :subject, dependent: :destroy
has_many :storylines, -> { order('pageflow_storylines.position ASC') }

has_many :storylines, -> { order('pageflow_storylines.position ASC') }, dependent: :destroy
has_many :chapters, -> { order('position ASC') }, through: :storylines
has_many :pages, -> { reorder(PAGE_ORDER) }, through: :storylines

has_many :file_usages
has_many :file_usages, dependent: :destroy

has_many :image_files, -> { extending WithFileUsageExtension },
:through => :file_usages, :source => :file, :source_type => 'Pageflow::ImageFile'
Expand All @@ -39,6 +40,8 @@ class Revision < ActiveRecord::Base

scope :publications, -> { where('published_at IS NOT NULL') }
scope :publications_and_user_snapshots, -> { where('published_at IS NOT NULL OR snapshot_type = "user"') }
scope :user_snapshots, -> { where('snapshot_type = "user"') }
scope :auto_snapshots, -> { where('snapshot_type = "auto"') }

validates :entry, :presence => true
validates :creator, :presence => true, :if => :published?
Expand Down
2 changes: 1 addition & 1 deletion app/models/pageflow/storyline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Storyline < ActiveRecord::Base

belongs_to :revision, touch: true

has_many :chapters, -> { order('pageflow_chapters.position ASC') }
has_many :chapters, -> { order('pageflow_chapters.position ASC') }, dependent: :destroy
has_many :pages, through: :chapters

delegate :entry, to: :revision
Expand Down
14 changes: 14 additions & 0 deletions lib/tasks/pageflow_tasks.rake
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,18 @@ namespace :pageflow do
system('bin/npm run build')
end
end

namespace :prune_auto_snapshots_jobs do
desc 'Enqueue jobs to destroy old auto snapshot revisions'
task :enqueue => :environment do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the new Ruby 1.9 hash syntax.

options = {
created_before: ENV['CREATED_BEFORE'] ? Time.parse(ENV['CREATED_BEFORE']) : 1.month.ago,
keep_count: ENV.fetch('KEEP_COUNT', 20)
}

Pageflow::AutoSnapshotPruning.dirty_entry_ids(options).each do |entry_id|
Resque.enqueue(Pageflow::PruneAutoSnapshotsJob, entry_id, options)
end
end
end
end
18 changes: 18 additions & 0 deletions spec/jobs/pageflow/prune_auto_snapshots_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'spec_helper'

module Pageflow
describe PruneAutoSnapshotsJob do
it 'destroys old auto snapshots' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.snapshot(creator: user) }
end

PruneAutoSnapshotsJob.perform(entry.id, keep_count: 2, created_before: 1.month.ago)

expect(entry.reload.revisions.auto_snapshots.count).to eq(2)
end
end
end
155 changes: 155 additions & 0 deletions spec/models/pageflow/auto_snapshot_pruning_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
require 'spec_helper'

module Pageflow
describe AutoSnapshotPruning do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block has too many lines. [107/25]

describe '.dirty_entry_ids' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block has too many lines. [45/25]

it 'includes entries with more than keep_count auto snapshots created before given time' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
5.times { entry.snapshot(creator: user) }
end

result = AutoSnapshotPruning.dirty_entry_ids(keep_count: 4, created_before: 1.month.ago)

expect(result).to include(entry.id)
end

it 'does not includes entries with less than keep_count auto snapshots' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
2.times { entry.snapshot(creator: user) }
end

result = AutoSnapshotPruning.dirty_entry_ids(keep_count: 4, created_before: 1.month.ago)

expect(result).not_to include(entry.id)
end

it 'does not includes entries with auto snapshots created after given date' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(1.day.ago) do
3.times { entry.snapshot(creator: user) }
end

result = AutoSnapshotPruning.dirty_entry_ids(keep_count: 2, created_before: 1.month.ago)

expect(result).not_to include(entry.id)
end

it 'does not includes entries with more than keep_count user snapshots' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.snapshot(creator: user, type: 'user') }
end

result = AutoSnapshotPruning.dirty_entry_ids(keep_count: 2, created_before: 1.month.ago)

expect(result).not_to include(entry.id)
end

it 'does not includes entries with more than keep_count publications' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.publish(creator: user) }
end

result = AutoSnapshotPruning.dirty_entry_ids(keep_count: 2, created_before: 1.month.ago)

expect(result).not_to include(entry.id)
end
end

describe '.prune' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block has too many lines. [58/25]

it 'destroy all but keep_count auto snapshots' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.snapshot(creator: user) }
end

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)

expect(entry.revisions.auto_snapshots.count).to eq(2)
end

it 'triggers dependent destroys down to pages' do
user = create(:user)
entry = create(:entry)
chapter = create(:chapter, storyline: entry.draft.storylines.first)
create(:page, chapter: chapter)

Timecop.freeze(2.month.ago) do
3.times { entry.snapshot(creator: user) }
end

expect {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parenthesize the param change { Pageflow::Page.count } to make sure that the block will be associated with the change method call.

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)
}.to change { Pageflow::Page.count }
end

it 'destroys oldest auto snapshots first' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(4.month.ago) { entry.snapshot(creator: user) }
Timecop.freeze(3.month.ago) { entry.snapshot(creator: user) }
Timecop.freeze(2.month.ago) { entry.snapshot(creator: user) }

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)
timestamps = entry.revisions.auto_snapshots.map(&:created_at)

expect(timestamps).to match_array([2.month.ago, 3.month.ago])
end

it 'ignores auto snapshots created after given data' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(4.month.ago) { entry.snapshot(creator: user) }
Timecop.freeze(3.days.ago) { entry.snapshot(creator: user) }
Timecop.freeze(2.days.ago) { entry.snapshot(creator: user) }

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)

expect(entry.revisions.auto_snapshots.count).to eq(3)
end

it 'ignores user snapshots' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.snapshot(creator: user, type: 'user') }
end

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)

expect(entry.revisions.user_snapshots.count).to eq(3)
end

it 'ignores publications' do
user = create(:user)
entry = create(:entry)

Timecop.freeze(2.month.ago) do
3.times { entry.publish(creator: user) }
end

AutoSnapshotPruning.prune(entry, keep_count: 2, created_before: 1.month.ago)

expect(entry.revisions.publications.count).to eq(3)
end
end
end
end