diff --git a/app/services/ci/retry_pipeline_service.rb b/app/services/ci/retry_pipeline_service.rb
index ca19b828e1c09fde63d9e5ec7e9ab1a52ae4151e..574561adc4ce7959169bc0504586438a8abc5185 100644
--- a/app/services/ci/retry_pipeline_service.rb
+++ b/app/services/ci/retry_pipeline_service.rb
@@ -1,22 +1,21 @@
 module Ci
   class RetryPipelineService < ::BaseService
+    include Gitlab::OptimisticLocking
+
     def execute(pipeline)
       unless can?(current_user, :update_pipeline, pipeline)
         raise Gitlab::Access::AccessDeniedError
       end
 
-      pipeline.builds.failed_or_canceled.tap do |builds|
-        stage_idx = builds.order('stage_idx ASC')
-          .pluck('DISTINCT stage_idx').first
-
-        pipeline.mark_as_processable_after_stage(stage_idx)
+      pipeline.builds.failed_or_canceled.find_each do |build|
+        next unless build.retryable?
 
-        builds.find_each do |build|
-          next unless build.retryable?
+        Ci::RetryBuildService.new(project, current_user)
+          .reprocess(build)
+      end
 
-          Ci::RetryBuildService.new(project, current_user)
-            .reprocess(build)
-        end
+      pipeline.builds.skipped.find_each do |skipped|
+        retry_optimistic_lock(skipped) { |build| build.process }
       end
 
       MergeRequests::AddTodoWhenBuildFailsService
diff --git a/lib/gitlab/optimistic_locking.rb b/lib/gitlab/optimistic_locking.rb
index 879d46446b398e83eb0ea8374970e97cd3313562..e0b2286f1dcf87f5c0c409261815a5b9cd631e51 100644
--- a/lib/gitlab/optimistic_locking.rb
+++ b/lib/gitlab/optimistic_locking.rb
@@ -1,6 +1,6 @@
 module Gitlab
   module OptimisticLocking
-    extend self
+    module_function
 
     def retry_lock(subject, retries = 100, &block)
       loop do
@@ -15,5 +15,7 @@ module Gitlab
         end
       end
     end
+
+    alias :retry_optimistic_lock :retry_lock
   end
 end