post regenerations: regenerate posts asynchronously.

Regenerate posts asynchronously using a delayed job.

Regenerating a post can be slow because it involves downloading the
original file, regenerating the thumbnails, and redistributing the new
thumbnails back to the image servers. It's better to run this in the
background, especially if a user is trying to regenerate posts in bulk.

The downside is there's no notification to the user when the regeneration
is complete. You have to check the modactions log to see when it's finished.
This commit is contained in:
evazion
2021-01-04 18:16:43 -06:00
parent df44937c57
commit b6f9c9a866
6 changed files with 62 additions and 8 deletions

View File

@@ -1,9 +1,10 @@
class PostRegenerationsController < ApplicationController
respond_to :xml, :json, :js
respond_to :xml, :json, :html
def create
@post = authorize Post.find(params[:post_id]), :regenerate?
@post.regenerate!(params[:category], CurrentUser.user)
@post.regenerate_later!(params[:category], CurrentUser.user)
flash[:notice] = "Post regeneration scheduled, press Ctrl+F5 in a few seconds to refresh the image"
respond_with(@post)
end

View File

@@ -0,0 +1,8 @@
class RegeneratePostJob < ApplicationJob
queue_as :default
queue_with_priority 20
def perform(post:, category:, user:)
post.regenerate!(category, user)
end
end

View File

@@ -1326,6 +1326,10 @@ class Post < ApplicationRecord
end
concerning :RegenerationMethods do
def regenerate_later!(category, user)
RegeneratePostJob.perform_later(post: self, category: category, user: user)
end
def regenerate!(category, user)
if category == "iqdb"
update_iqdb_async

View File

@@ -1 +0,0 @@
Danbooru.notice("Post regenerated");

View File

@@ -88,6 +88,6 @@
<% end %>
<% if policy(post).regenerate? %>
<li id="post-option-regenerate-preview"><%= link_to "Regenerate image", post_regenerations_path(post_id: post.id, category: "resizes"), remote: true, method: :post, "data-confirm": "This will regenerate the posts's thumbnail images. Are you sure?" %></li>
<li id="post-option-regenerate-preview"><%= link_to "Regenerate image", post_regenerations_path(post_id: post.id, category: "resizes"), method: :post, "data-confirm": "This will regenerate the posts's thumbnail images. Are you sure?" %></li>
<% end %>
</ul>

View File

@@ -4,21 +4,63 @@ class PostRegenerationsControllerTest < ActionDispatch::IntegrationTest
context "The post regenerations controller" do
setup do
@mod = create(:moderator_user, name: "yukari", created_at: 1.month.ago)
as(@mod) do
@post = create(:post, source: "https://google.com", tag_string: "touhou")
end
@upload = assert_successful_upload("test/files/test.jpg", user: @mod)
@post = @upload.post
end
context "create action" do
should "render" do
post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" }
assert_response :success
assert_redirected_to @post
assert_enqueued_jobs(1, only: RegeneratePostJob)
end
should "not allow non-mods to regenerate posts" do
post_auth post_regenerations_path, create(:user), params: { post_id: @post.id, category: "iqdb" }
assert_response 403
end
context "for an IQDB regeneration" do
should "regenerate IQDB" do
mock_iqdb_service!
Post.iqdb_sqs_service.expects(:send_message).with("update\n#{@post.id}\n#{@post.preview_file_url}")
post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" }
perform_enqueued_jobs
end
should "log a mod action" do
post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" }
perform_enqueued_jobs
assert_equal(@mod, ModAction.last.creator)
assert_equal("post_regenerate_iqdb", ModAction.last.category)
assert_equal("@#{@mod.name} regenerated IQDB for post ##{@post.id}", ModAction.last.description)
end
end
context "for an image sample regeneration" do
should "regenerate missing thumbnails" do
@preview_file_size = @post.file(:preview).size
@post.storage_manager.delete_file(@post.id, @post.md5, @post.file_ext, :preview)
assert_raise(Errno::ENOENT) { @post.file(:preview) }
post_auth post_regenerations_path, @mod, params: { post_id: @post.id }
perform_enqueued_jobs
assert_equal(@preview_file_size, @post.file(:preview).size)
end
should "log a mod action" do
post_auth post_regenerations_path, @mod, params: { post_id: @post.id }
perform_enqueued_jobs
assert_equal(@mod, ModAction.last.creator)
assert_equal("post_regenerate", ModAction.last.category)
assert_equal("@#{@mod.name} regenerated image samples for post ##{@post.id}", ModAction.last.description)
end
end
end
end
end