diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index f5790f9744f61922a90a266707077c8ee79bfaf5..fb0fbb43fb1763b1bd4b0cecf5acff3639690743 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -3,7 +3,7 @@ module Ci
     extend Ci::Model
 
     RUNNER_QUEUE_EXPIRY_TIME = 60.minutes
-    LAST_CONTACT_TIME = 1.hour.ago
+    ONLINE_CONTACT_TIMEOUT = 1.hour
     AVAILABLE_SCOPES = %w[specific shared active paused online].freeze
     FORM_EDITABLE = %i[description tag_list active run_untagged locked].freeze
 
@@ -19,7 +19,7 @@ module Ci
     scope :shared, ->() { where(is_shared: true) }
     scope :active, ->() { where(active: true) }
     scope :paused, ->() { where(active: false) }
-    scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
+    scope :online, ->() { where('contacted_at > ?', contact_time_deadline) }
     scope :ordered, ->() { order(id: :desc) }
 
     scope :owned_or_shared, ->(project_id) do
@@ -59,6 +59,10 @@ module Ci
       where(t[:token].matches(pattern).or(t[:description].matches(pattern)))
     end
 
+    def self.contact_time_deadline
+      ONLINE_CONTACT_TIMEOUT.ago
+    end
+
     def set_default_values
       self.token = SecureRandom.hex(15) if self.token.blank?
     end
@@ -80,7 +84,7 @@ module Ci
     end
 
     def online?
-      contacted_at && contacted_at > LAST_CONTACT_TIME
+      contacted_at && contacted_at > self.class.contact_time_deadline
     end
 
     def status
diff --git a/changelogs/unreleased/fix-runner_online_check.yml b/changelogs/unreleased/fix-runner_online_check.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bc0de979b4c0d663c691865f102098a1c717c69a
--- /dev/null
+++ b/changelogs/unreleased/fix-runner_online_check.yml
@@ -0,0 +1,4 @@
+---
+title: Fix offline runner detection
+merge_request: 11751
+author: Alessio Caiazza