diff --git a/.gitignore b/.gitignore index 963e1bfc7b75f8a2afb15e0accdde1e001b17af0..1c9a6b8c5cf4d97c289f7d7009457adab7175d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ vendor/bundle/ vendor/cache/ config/database.yml config/oidc_key.pem +config/schedule.yml # Generated files log/ diff --git a/Changelog.md b/Changelog.md index 86eb81f1b73213056d34f27eb2c940c92edb29c9..64c2ed26e25c60cfaf1d6ef44c68cbd5df458cc7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ ## Refactor * Remove the 'make contacts in this aspect visible to each other' option [#7769](https://github.com/diaspora/diaspora/pull/7769) * Remove the requirement to have at least two users to disable the /podmin redirect [#7783](https://github.com/diaspora/diaspora/pull/7783) +* Randomize start times of daily Sidekiq-Cron jobs [#7787](https://github.com/diaspora/diaspora/pull/7787) ## Bug fixes * Prefill conversation form on contacts page only with mutual contacts [#7744](https://github.com/diaspora/diaspora/pull/7744) diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 50e2e07da5701ffa0ab6fc2a3fdeefa0bcd1c04d..7b2a28a24b1cb94653f63a3c80291b0405ef5b22 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -54,9 +54,3 @@ end Sidekiq.configure_client do |config| config.redis = AppConfig.get_redis_options end - -schedule_file = "config/schedule.yml" - -if File.exist?(schedule_file) && Sidekiq.server? - Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file) -end diff --git a/config/initializers/sidekiq_scheduled.rb b/config/initializers/sidekiq_scheduled.rb new file mode 100644 index 0000000000000000000000000000000000000000..ac9140e380dfa9b3f34f8a17aeed9c156c30e723 --- /dev/null +++ b/config/initializers/sidekiq_scheduled.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +# Some recurring background jobs can take a lot of resources, and others even +# include pinging other pods, like recurring_pod_check. Having all jobs run at +# 0 UTC causes a high local load, as well as a little bit of DDoSing through +# the network, as pods try to ping each other. +# +# As Sidekiq-Cron does not support random offsets, we have to take care of that +# ourselves, so let's add jobs with random work times. + +# rubocop:disable Metrics/MethodLength +def default_job_config + random_hour = lambda { rand(24) } + random_minute = lambda { rand(60) } + + { + check_birthday: { + "cron": "0 0 * * *", + "class": "Workers::CheckBirthday" + }, + + clean_cached_files: { + "cron": "#{random_minute.call} #{random_hour.call} * * *", + "class": "Workers::CleanCachedFiles" + }, + + cleanup_old_exports: { + "cron": "#{random_minute.call} #{random_hour.call} * * *", + "class": "Workers::CleanupOldExports" + }, + + queue_users_for_removal: { + "cron": "#{random_minute.call} #{random_hour.call} * * *", + "class": "Workers::QueueUsersForRemoval" + }, + + recheck_scheduled_pods: { + "cron": "*/30 * * * *", + "class": "Workers::RecheckScheduledPods" + }, + + recurring_pod_check: { + "cron": "#{random_minute.call} #{random_hour.call} * * *", + "class": "Workers::RecurringPodCheck" + } + } +end +# rubocop:enable Metrics/MethodLength + +def valid_config?(path) + return false unless File.exist?(path) + + current_config = YAML.load_file(path) + + # If they key don't match the current default config keys, a new job has + # been added, so we nede to regenerate the config to have the new job + # running + return false unless current_config.keys == default_job_config.keys + + # If recurring_pod_check is still running at midnight UTC, the config file + # is probably from a previous version, and that's bad, so we need to + # regenerate + current_config[:recurring_pod_check][:cron] != "0 0 * * *" +end + +def regenerate_config(path) + job_config = default_job_config + File.open(path, "w") do |schedule_file| + schedule_file.write(job_config.to_yaml) + end +end + +if Sidekiq.server? + schedule_file_path = Rails.root.join("config", "schedule.yml") + regenerate_config(schedule_file_path) unless valid_config?(schedule_file_path) + + Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file_path) +end diff --git a/config/schedule.rb.example b/config/schedule.rb.example deleted file mode 100644 index 319c9aedbe72ced865360e714aedaf1b6bc260ef..0000000000000000000000000000000000000000 --- a/config/schedule.rb.example +++ /dev/null @@ -1,25 +0,0 @@ -# Use this file to easily define all of your cron jobs. -# -# It's helpful, but not entirely necessary to understand cron before proceeding. -# http://en.wikipedia.org/wiki/Cron - -# set :environment, "production" - -# Example: -set :output, File.join( File.dirname( __FILE__ ), '..', 'logs', 'scheduled_tasks.log' ) - -every 1.day, :at => '3:00 am' do - rake 'maintenance:clear_carrierwave_temp_uploads' -end - -# every 2.hours do -# command "/usr/bin/some_great_command" -# runner "MyModel.some_method" -# rake "some:great:rake:task" -# end -# -# every 4.days do -# runner "AnotherModel.prune_old_records" -# end - -# Learn more: http://github.com/javan/whenever diff --git a/config/schedule.yml b/config/schedule.yml deleted file mode 100644 index 8e6f2361f830646549947115eb7b289007cc11b5..0000000000000000000000000000000000000000 --- a/config/schedule.yml +++ /dev/null @@ -1,23 +0,0 @@ -clean_cached_files: - cron: "0 0 * * *" - class: "Workers::CleanCachedFiles" - -queue_users_for_removal: - cron: "0 0 * * *" - class: "Workers::QueueUsersForRemoval" - -recurring_pod_check: - cron: "0 0 * * *" - class: "Workers::RecurringPodCheck" - -recheck_scheduled_pods: - cron: "*/30 * * * *" - class: "Workers::RecheckScheduledPods" - -check_birthday: - cron: "0 0 * * *" - class: "Workers::CheckBirthday" - -cleanup_old_exports: - cron: "0 0 * * *" - class: "Workers::CleanupOldExports"