Skip to content

Commit

Permalink
Creates first version of UI consisting of queue details and sidekiq s…
Browse files Browse the repository at this point in the history
…tats:

- Adds route for UI to config
- Controller fetches metrics from service class
- Service class renamed and fetches data and manipulates it as needed
- View created using haml template to display information
- Adds descriptions of queues / metrics in locales en.yml
  • Loading branch information
empty-codes committed Dec 18, 2024
1 parent d19a4a0 commit 2978545
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 31 deletions.
7 changes: 6 additions & 1 deletion app/controllers/system_status_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# frozen_string_literal: true

class SystemStatusController < ApplicationController
# service = SystemMetricsService.new
def index
system_metrics = GetSystemMetrics.new

@sidekiq_stats = system_metrics.fetch_sidekiq_stats
@queue_metrics = system_metrics.fetch_queue_management_metrics
end
end
82 changes: 52 additions & 30 deletions app/services/get_system_metrics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,73 @@

require 'sidekiq/api'

class SystemMetricsService
class GetSystemMetrics
def initialize
@queues = YAML.load_file('config/sidekiq.yml')[:queues]
.reject { |queue_name| queue_name == 'very_long_update' }
fetch_sidekiq_stats
end

def fetch_sidekiq_stats
stats = Sidekiq::Stats.new

@processed_jobs_stat = stats.processed
@failed_jobs_stat = stats.failed # Failed Job Retention
@enqueued_jobs_stat = stats.enqueued
@scheduled_jobs_stat = stats.scheduled_size

# also allow stats from selected dates to be viewed
# using Stats::History
{
enqueued_jobs: stats.enqueued,
active_jobs: stats.processes_size
}
end

# def fetch_system_health_metrics
# end
def fetch_queue_management_metrics
queues = []
paused_queues = []
all_operational = true

# def fetch_reliability_metrics
# end
@queues.each do |queue_name|
queue = Sidekiq::Queue.new(queue_name)
queues << get_queue_data(queue)

# def fetch_availability_metrics
# end
if queue.paused?
all_operational = false
paused_queues << queue_name
end
end

# def fetch_processing_efficiency_metrics
# end
{
queues:,
paused_queues:,
all_operational:
}
end

# def fetch_resource_utilization_metrics
# end
def get_queue_data(queue)
{
name: queue.name,
size: queue.size,
status: queue.size.zero? ? 'No pending jobs' : 'Pending jobs',
latency: convert_latency(queue.latency)
}
end

def fetch_queue_management_metrics
# Queue latency; how long jobs wait in the queue before processing
@queues.map do |queue_name|
queue = Sidekiq::Queue.new(queue_name)
{
name: queue.name,
size: queue.size,
latency: queue.latency
}
def convert_latency(seconds)
case seconds
when 0...60
"#{seconds.to_i} second#{'s' unless seconds == 1}"
when 60...3600
format_time(seconds, 60, 'minute', 'second')
when 3600...86400
format_time(seconds, 3600, 'hour', 'minute')
else
format_time(seconds, 86400, 'day', 'hour')
end
end

# def fetch_data_freshness_metrics
# end
def format_time(seconds, unit, main_unit_name, sub_unit_name)
main_unit = (seconds / unit).to_i
remaining_seconds = (seconds % unit).to_i
result = "#{main_unit} #{main_unit_name}#{'s' unless main_unit == 1}"
if remaining_seconds.positive?
sub_unit_value = (remaining_seconds / (unit / 60)).to_i
result += " #{sub_unit_value} #{sub_unit_name}#{'s' unless sub_unit_value == 1}"
end
result
end
end
66 changes: 66 additions & 0 deletions app/views/system_status/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
.container.queues
.module
.section-header
%h3 Queues Overview
.notification
.container
- if @queue_metrics[:all_operational]
%p All Queues Operational
- else
%p All Queues Operational except:
.notifications
.notice
.container
- @queue_metrics[:paused_queues].each do |queue_name|
%p= queue_name.humanize
%br/

%table.table.table--hoverable
%thead
%tr
%th Queue
%th Purpose
%th Status
%th
.tooltip-trigger
= t("status.size")
%span.tooltip-indicator
.tooltip.dark
%p= t("status.size_doc")
%th
.tooltip-trigger
= t("status.latency")
%span.tooltip-indicator
.tooltip.dark
%p= t("status.latency_doc")
%tbody
- @queue_metrics[:queues].each do |queue|
%tr{ class: queue[:size].zero? ? "table-row--success" : "table-row--warning" }
%td
.tooltip-trigger
= t("status.#{queue[:name]}")
%span.tooltip-indicator
.tooltip.dark
%p= t("status.#{queue[:name]}_description")
%td= t("status.#{queue[:name]}_doc")
%td= queue[:status]
%td= queue[:size]
%td= queue[:latency]

.container.sidekiq_stats
%br/
%h3 Sidekiq Stats
.stat-display
- @sidekiq_stats.each do |key, value|
.stat-display__stat.tooltip-trigger
.stat-display__value= value
%small= key.to_s.humanize

.tooltip.dark
- case key
- when :enqueued_jobs
%p= t("status.enqueued_jobs_doc")
- when :active_jobs
%p= t("status.active_jobs_doc")
- else
%p No additional info available
28 changes: 28 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,34 @@ en:
already_is_not: "%{username} is not a Special User!"
demote_success: "%{username} is now just a user."

status:
active_jobs: Active jobs
active_jobs_doc: The number of currently processing jobs.
constant_update: Constant update
constant_update_description: Constant updates are independent of the main course stats, pulling in revision metadata, generating alerts, and doing other data and network-intensive tasks, for all current courses.
constant_update_doc: Handles transactional jobs like wiki edits and sending email.
daily_update: Daily update
daily_update_description: This pulls in additional data and performs other tasks that do not need to be done many times per day.
daily_update_doc: Handles once-daily long-running data update tasks.
default: Default
default_description: Schedule course updates by sorting courses into queues depending on how long they run.
default_doc: Handles frequently-run tasks like adding courses to the update queues.
enqueued_jobs: Enqueued jobs
enqueued_jobs_doc: The number of currently enqueued jobs in all queues.
latency: Latency
latency_doc: The waiting time for jobs to start processing in the queue. High latency may indicate a busy system or processing delays.
long_update: Long update
long_update_description: Long updates process courses with more than 10,000 revisions.
long_update_doc: Handles updates for large courses.
medium_update: Medium update
medium_update_description: Medium updates process courses with fewer than 10,000 revisions.
medium_update_doc: Handles updates for typical-sized courses.
short_update: Short update
short_update_description: Short updates process courses with fewer than 1,000 revisions.
short_update_doc: Handles updates for small courses.
size: Size
size_doc: The number of jobs within a queue.

# Suggestions source: https://en.wikipedia.org/wiki/Template:Grading_scheme
suggestions:
editing: Editing Suggestions
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@
get '/private_information' => 'about_this_site#private_information'
get '/styleguide' => 'styleguide#index'

get '/status' => 'system_status#index'

# Errors
match '/404', to: 'errors#file_not_found', via: :all
match '/422', to: 'errors#unprocessable', via: :all
Expand Down

0 comments on commit 2978545

Please sign in to comment.