diff --git a/modules/meeting/app/services/recurring_meetings/update_service.rb b/modules/meeting/app/services/recurring_meetings/update_service.rb index b7ae23888e73..80fcf24e97de 100644 --- a/modules/meeting/app/services/recurring_meetings/update_service.rb +++ b/modules/meeting/app/services/recurring_meetings/update_service.rb @@ -36,6 +36,7 @@ def after_perform(call) return call unless call.success? cleanup_cancelled_schedules(call.result) + reschedule_init_job(call.result) update_template(call) end @@ -59,5 +60,27 @@ def cleanup_cancelled_schedules(recurring_meeting) scheduled.delete unless occurring end end + + def reschedule_init_job(recurring_meeting) + return unless should_reschedule?(recurring_meeting) + + concurrency_key = InitNextOccurrenceJob.unique_key(recurring_meeting) + + # Delete all scheduled jobs for this meeting + GoodJob::Job.where(finished_at: nil, concurrency_key:).delete_all + + InitNextOccurrenceJob + .set(wait_until: recurring_meeting.next_occurrence.to_time) + .perform_later(recurring_meeting) + end + + def should_reschedule?(recurring_meeting) + return false if recurring_meeting.next_occurrence.nil? + + recurring_meeting + .previous_changes + .keys + .intersect?(%w[frequency start_date start_time start_time_hour iterations interval end_after end_date]) + end end end diff --git a/modules/meeting/app/workers/recurring_meetings/init_next_occurrence_job.rb b/modules/meeting/app/workers/recurring_meetings/init_next_occurrence_job.rb index dd6be44930d6..8d818cad011e 100644 --- a/modules/meeting/app/workers/recurring_meetings/init_next_occurrence_job.rb +++ b/modules/meeting/app/workers/recurring_meetings/init_next_occurrence_job.rb @@ -32,9 +32,13 @@ class InitNextOccurrenceJob < ApplicationJob good_job_control_concurrency_with( perform_limit: 1, - key: -> { "#{self.class.name}-#{queue_name}-#{arguments.first.id}" } + key: -> { self.class.unique_key(arguments.first) } ) + def self.unique_key(recurring_meeting) + "RecurringMeetings::InitNextOccurrenceJob-#{recurring_meeting.id}" + end + attr_accessor :recurring_meeting def perform(recurring_meeting) diff --git a/modules/meeting/spec/services/recurring_meetings/update_service_integration_spec.rb b/modules/meeting/spec/services/recurring_meetings/update_service_integration_spec.rb index ff3a69ae6160..11aab02ae46e 100644 --- a/modules/meeting/spec/services/recurring_meetings/update_service_integration_spec.rb +++ b/modules/meeting/spec/services/recurring_meetings/update_service_integration_spec.rb @@ -33,7 +33,7 @@ shared_let(:user) do create(:user, member_with_permissions: { project => %i(view_meetings edit_meetings) }) end - shared_let(:series) do + shared_let(:series, refind: true) do create(:recurring_meeting, project:, start_time: Time.zone.today + 10.hours, @@ -83,4 +83,40 @@ end end end + + describe "rescheduling job" do + context "when updating the title" do + let(:params) do + { title: "New title" } + end + + it "does not reschedule" do + expect { service_result }.not_to have_enqueued_job(RecurringMeetings::InitNextOccurrenceJob) + expect(service_result).to be_success + end + end + + context "when updating the frequency and start_time" do + let(:params) do + { start_time: Time.zone.today + 2.days + 11.hours } + end + + before do + ActiveJob::Base.disable_test_adapter + RecurringMeetings::InitNextOccurrenceJob + .set(wait_until: Time.zone.today + 1.day + 10.hours) + .perform_later(series) + end + + it "reschedules" do + job = GoodJob::Job.find_by(job_class: "RecurringMeetings::InitNextOccurrenceJob") + expect(job.scheduled_at).to eq Time.zone.today + 1.day + 10.hours + expect(service_result).to be_success + expect { job.reload }.to raise_error(ActiveRecord::RecordNotFound) + + new_job = GoodJob::Job.find_by(job_class: "RecurringMeetings::InitNextOccurrenceJob") + expect(new_job.scheduled_at).to eq Time.zone.today + 2.days + 11.hours + end + end + end end