Isolate report rendering in separate child process

Sidekiq doesn't have any features to limit memory usage or execution
time. We need a separate process for this. Forking avoids the boot time
of a fresh process and copy-on-write ensures minimal memory overheads.
This commit is contained in:
Maikel Linke
2023-01-11 15:30:58 +11:00
committed by Filipe
parent a177f4c066
commit b19456535d
4 changed files with 52 additions and 2 deletions

View File

@@ -695,6 +695,7 @@ Rails/ApplicationJob:
- 'app/jobs/report_job.rb'
- 'app/jobs/subscription_confirm_job.rb'
- 'app/jobs/subscription_placement_job.rb'
- 'spec/services/job_processor_spec.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).

View File

@@ -55,10 +55,11 @@ module Admin
def render_report_as(format)
if OpenFoodNetwork::FeatureToggle.enabled?(:background_reports, spree_current_user)
job = ReportJob.perform_later(
job = ReportJob.new
JobProcessor.perform_forked(
job,
report_class, spree_current_user, params, format
)
sleep 1 until job.done?
# This result has been rendered by Rails in safe mode already.
job.result.html_safe # rubocop:disable Rails/OutputSafety

View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
# Forks into a separate process to contain memory usage and timeout errors.
class JobProcessor
def self.perform_forked(job, *args)
fork do
Process.setproctitle("Job worker #{job.job_id}")
job.perform(*args)
# Exit is not a good idea within a Rails process but Rubocop doesn't know
# that we are in a forked process.
exit # rubocop:disable Rails/Exit
end
Process.waitall
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
class TestJob < ActiveJob::Base
def initialize
@file = Tempfile.new("test-job-result")
super
end
def perform(message)
@file.write(message)
end
def result
@file.rewind
@file.read
end
end
describe JobProcessor do
describe ".perform_forked" do
let(:job) { TestJob.new }
it "executes a job" do
JobProcessor.perform_forked(job, "hello")
expect(job.result).to eq "hello"
end
end
end