housekeeping_service.rb 2.32 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5 6 7
# Projects::HousekeepingService class
#
# Used for git housekeeping
#
# Ex.
8
#   Projects::HousekeepingService.new(project).execute
9 10 11
#
module Projects
  class HousekeepingService < BaseService
12 13
    # Timeout set to 24h
    LEASE_TIMEOUT = 86400
14

15 16 17 18 19 20
    class LeaseTaken < StandardError
      def to_s
        "Somebody already triggered housekeeping for this project in the past #{LEASE_TIMEOUT / 60} minutes"
      end
    end

21
    def initialize(project, task = nil)
22
      @project = project
23
      @task = task
24 25 26
    end

    def execute
Jacob Vosmaer's avatar
Jacob Vosmaer committed
27 28
      lease_uuid = try_obtain_lease
      raise LeaseTaken unless lease_uuid.present?
Jacob Vosmaer's avatar
Jacob Vosmaer committed
29

30 31
      yield if block_given?

Jacob Vosmaer's avatar
Jacob Vosmaer committed
32
      execute_gitlab_shell_gc(lease_uuid)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
33 34 35
    end

    def needed?
Jacob Vosmaer's avatar
Jacob Vosmaer committed
36
      pushes_since_gc > 0 && period_match? && housekeeping_enabled?
Jacob Vosmaer's avatar
Jacob Vosmaer committed
37 38 39
    end

    def increment!
Yorick Peterse's avatar
Yorick Peterse committed
40 41
      Gitlab::Metrics.measure(:increment_pushes_since_gc) do
        @project.increment_pushes_since_gc
42
      end
43 44 45 46
    end

    private

Jacob Vosmaer's avatar
Jacob Vosmaer committed
47 48
    def execute_gitlab_shell_gc(lease_uuid)
      GitGarbageCollectWorker.perform_async(@project.id, task, lease_key, lease_uuid)
49
    ensure
Jacob Vosmaer's avatar
Jacob Vosmaer committed
50 51 52 53
      if pushes_since_gc >= gc_period
        Gitlab::Metrics.measure(:reset_pushes_since_gc) do
          @project.reset_pushes_since_gc
        end
54 55 56
      end
    end

57
    def try_obtain_lease
58
      Gitlab::Metrics.measure(:obtain_housekeeping_lease) do
Jacob Vosmaer's avatar
Jacob Vosmaer committed
59
        lease = ::Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT)
60 61
        lease.try_obtain
      end
62
    end
Jacob Vosmaer's avatar
Jacob Vosmaer committed
63 64 65 66 67 68 69 70 71 72

    def lease_key
      "project_housekeeping:#{@project.id}"
    end

    def pushes_since_gc
      @project.pushes_since_gc
    end

    def task
73 74
      return @task if @task

Jacob Vosmaer's avatar
Jacob Vosmaer committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88
      if pushes_since_gc % gc_period == 0
        :gc
      elsif pushes_since_gc % full_repack_period == 0
        :full_repack
      else
        :incremental_repack
      end
    end

    def period_match?
      [gc_period, full_repack_period, repack_period].any? { |period| pushes_since_gc % period == 0 }
    end

    def housekeeping_enabled?
89
      Gitlab::CurrentSettings.housekeeping_enabled
Jacob Vosmaer's avatar
Jacob Vosmaer committed
90 91 92
    end

    def gc_period
93
      Gitlab::CurrentSettings.housekeeping_gc_period
Jacob Vosmaer's avatar
Jacob Vosmaer committed
94 95 96
    end

    def full_repack_period
97
      Gitlab::CurrentSettings.housekeeping_full_repack_period
Jacob Vosmaer's avatar
Jacob Vosmaer committed
98 99 100
    end

    def repack_period
101
      Gitlab::CurrentSettings.housekeeping_incremental_repack_period
Jacob Vosmaer's avatar
Jacob Vosmaer committed
102
    end
103 104
  end
end