| 1 | # frozen_string_literal: true |
| 2 | |
| 3 | # Syncs one mirror repository from its upstream. Enqueued on a schedule by |
| 4 | # MirrorSyncSchedulerJob and (optionally) by a GitHub push webhook. Marks the |
| 5 | # repo's sync status so the UI can show last-synced time and surface failures. |
| 6 | class MirrorSyncJob < ApplicationJob |
| 7 | queue_as :default |
| 8 | |
| 9 | def perform(repository_id) |
| 10 | repo = Repository.find_by(id: repository_id) |
| 11 | return if repo.nil? || !repo.mirror? |
| 12 | |
| 13 | repo.update!(mirror_status: "syncing") |
| 14 | MirrorSyncService.sync(repo) |
| 15 | repo.update!(mirror_status: "ok", mirror_synced_at: Time.current, mirror_error: nil) |
| 16 | rescue ImportUrlValidator::InvalidUrl => e |
| 17 | # Upstream now resolves somewhere unsafe (e.g. DNS rebinding) — stop, don't |
| 18 | # fetch, and surface it. |
| 19 | repo&.update!(mirror_status: "failed", mirror_error: "Upstream is no longer a valid public URL: #{e.message}") |
| 20 | rescue MirrorSyncService::SyncError => e |
| 21 | repo&.update!(mirror_status: "failed", mirror_error: e.message) |
| 22 | rescue StandardError => e |
| 23 | Rails.logger.error("Mirror sync failed for repo #{repository_id}: #{e.class}: #{e.message}") |
| 24 | repo&.update!(mirror_status: "failed", mirror_error: "Sync failed unexpectedly.") |
| 25 | end |
| 26 | end |