summaryrefslogtreecommitdiff
path: root/app/services/ci/pipeline_schedules/calculate_next_run_service.rb
blob: 9c8f6b47288ae512472d72864bba614d7f4eb171 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# frozen_string_literal: true

module Ci
  module PipelineSchedules
    class CalculateNextRunService < BaseService
      include Gitlab::Utils::StrongMemoize

      def execute(schedule, fallback_method:)
        @schedule = schedule

        return fallback_method.call unless ::Feature.enabled?(:ci_daily_limit_for_pipeline_schedules, project, default_enabled: :yaml)
        return fallback_method.call unless plan_cron&.cron_valid?

        now = Time.zone.now
        plan_min_run = plan_cron.next_time_from(now)

        schedule_next_run = schedule_cron.next_time_from(now)
        return schedule_next_run if worker_cron.match?(schedule_next_run) && plan_min_run <= schedule_next_run

        plan_next_run = plan_cron.next_time_from(schedule_next_run)
        return plan_next_run if worker_cron.match?(plan_next_run)

        worker_next_run = worker_cron.next_time_from(schedule_next_run)
        return worker_next_run if plan_min_run <= worker_next_run

        worker_cron.next_time_from(plan_next_run)
      end

      private

      def schedule_cron
        strong_memoize(:schedule_cron) do
          Gitlab::Ci::CronParser.new(@schedule.cron, @schedule.cron_timezone)
        end
      end

      def worker_cron
        strong_memoize(:worker_cron) do
          Gitlab::Ci::CronParser.new(worker_cron_expression, Time.zone.name)
        end
      end

      def plan_cron
        strong_memoize(:plan_cron) do
          daily_limit = @schedule.daily_limit

          next unless daily_limit

          every_x_minutes = (1.day.in_minutes / daily_limit).to_i

          Gitlab::Ci::CronParser.parse_natural("every #{every_x_minutes} minutes", Time.zone.name)
        end
      end

      def worker_cron_expression
        Settings.cron_jobs['pipeline_schedule_worker']['cron']
      end
    end
  end
end