diff --git a/.gitignore b/.gitignore index 963e1bfc7..1c9a6b8c5 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 86eb81f1b..64c2ed26e 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 50e2e07da..7b2a28a24 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 000000000..ac9140e38 --- /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 319c9aedb..000000000 --- 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 8e6f2361f..000000000 --- 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"