Class: Wurk::ApiController
- Inherits:
-
ApplicationController
- Object
- ActionController::Base
- ApplicationController
- Wurk::ApiController
- Includes:
- ActionController::Live
- Defined in:
- app/controllers/wurk/api_controller.rb
Overview
JSON APIs consumed by the React SPA. Action methods stay thin; mapping to the wire shape lives in ‘Wurk::Api::Serializers`, and pagination lives in `Wurk::Api::Pagination`. SSE lives in #stream.
Wire-compat: every payload field reads from the canonical Wurk inspector objects (Stats, Queue, RetrySet, ScheduledSet, DeadSet, ProcessSet, BatchSet, Cron::LoopSet) so dashboards stay aligned with the Redis schema in ‘docs/target/sidekiq-free,pro,ent.md`.
Constant Summary collapse
- STREAM_TICK_SECONDS =
2.0- STREAM_MAX_DURATION =
600.0- HISTORY_WINDOW_UNITS =
{ 's' => 1, 'm' => 60, 'h' => 3600, 'd' => 86_400 }.freeze
- DEFAULT_HISTORY_WINDOW =
24 * 3600
Instance Method Summary collapse
- #batch ⇒ Object
- #batches ⇒ Object
- #cron ⇒ Object
- #cron_history ⇒ Object
- #dead ⇒ Object
- #enqueue_cron ⇒ Object
-
#history ⇒ Object
Cluster-total throughput/failures time-series for the dashboard charts.
- #limiters ⇒ Object
-
#meta ⇒ Object
Boot-time flags the SPA reads once to shape the UI (e.g. hide destructive actions and show the read-only banner).
- #metrics ⇒ Object
- #metrics_for_job ⇒ Object
- #pause_cron ⇒ Object
- #processes ⇒ Object
- #queue ⇒ Object
- #queues ⇒ Object
- #reset_limiter ⇒ Object
- #retries ⇒ Object
- #scheduled ⇒ Object
- #search ⇒ Object
- #stats ⇒ Object
-
#stream ⇒ Object
SSE: one ‘event: stats` per tick with a fresh Stats snapshot.
- #unpause_cron ⇒ Object
Instance Method Details
#batch ⇒ Object
69 70 71 72 73 74 75 76 |
# File 'app/controllers/wurk/api_controller.rb', line 69 def batch status = ::Wurk::Batch::Status.new(params[:bid].to_s) return render(json: { error: 'unknown batch' }, status: :not_found) unless status.exists? render json: status.data.transform_keys(&:to_sym) rescue ::ArgumentError render json: { error: 'unknown batch' }, status: :not_found end |
#batches ⇒ Object
62 63 64 65 66 67 |
# File 'app/controllers/wurk/api_controller.rb', line 62 def batches set = ::Wurk::BatchSet.new page = ::Wurk::Api::Pagination.window(params) rows = ::Wurk::Api::Pagination.slice(set, page) { |status| status.data.transform_keys(&:to_sym) } render json: { total: set.size, page: page[:page], count: page[:count], batches: rows } end |
#cron ⇒ Object
89 90 91 92 |
# File 'app/controllers/wurk/api_controller.rb', line 89 def cron now = ::Time.now.to_i render json: ::Wurk::Cron::LoopSet.new.map { |lp| ::Wurk::Api::Serializers.cron_row(lp, now) } end |
#cron_history ⇒ Object
104 105 106 |
# File 'app/controllers/wurk/api_controller.rb', line 104 def cron_history render json: { lid: params[:lid].to_s, history: ::Wurk::Web::Enterprise::Periodic.history(params[:lid].to_s) } end |
#dead ⇒ Object
56 |
# File 'app/controllers/wurk/api_controller.rb', line 56 def dead = render_sorted_set(::Wurk::DeadSet.new) |
#enqueue_cron ⇒ Object
97 98 99 100 101 102 |
# File 'app/controllers/wurk/api_controller.rb', line 97 def enqueue_cron jid = ::Wurk::Web::Enterprise::Periodic.enqueue_now(params[:lid].to_s) return render(json: { error: 'unknown loop' }, status: :not_found) if jid.nil? render json: { ok: true, jid: jid } end |
#history ⇒ Object
Cluster-total throughput/failures time-series for the dashboard charts. ‘:bucket` is 1m/5m/1h; `?window=24h` (s/m/h/d suffix) is clamped to the bucket’s retention. Recharts-ready array under ‘series`.
129 130 131 132 133 134 135 |
# File 'app/controllers/wurk/api_controller.rb', line 129 def history window = parse_window(params[:window]) series = ::Wurk::Web::Enterprise::Historical.history(params[:bucket].to_s, window: window) render json: { bucket: params[:bucket].to_s, window: window, series: series.map { |row| ::Wurk::Api::Serializers.history_point(row) } } rescue ::ArgumentError => e render json: { error: e. }, status: :bad_request end |
#limiters ⇒ Object
78 79 80 81 82 |
# File 'app/controllers/wurk/api_controller.rb', line 78 def limiters names = ::Wurk::Web::Enterprise::Limits.list(filter: params[:substr]) page = ::Wurk::Api::Pagination.window(params) render json: { total: names.size, page: page[:page], count: page[:count], limiters: limiter_rows(names, page) } end |
#meta ⇒ Object
Boot-time flags the SPA reads once to shape the UI (e.g. hide destructive actions and show the read-only banner). Always a GET, so it stays reachable while read-only mode blocks mutations.
32 33 34 |
# File 'app/controllers/wurk/api_controller.rb', line 32 def render json: { read_only: ::Wurk::Web.config.read_only? } end |
#metrics ⇒ Object
108 109 110 111 112 113 114 |
# File 'app/controllers/wurk/api_controller.rb', line 108 def metrics minutes = ::Wurk::Api::Pagination.clamp_int(params[:minutes], 1, ::Wurk::Metrics::Query::MAX_MINUTES, 60) rows = ::Wurk::Web::Enterprise::Historical.top(minutes: minutes, class_filter: params[:substr]) render json: { minutes: minutes, top_jobs: rows.map { |(klass, totals)| ::Wurk::Api::Serializers.metric_row(klass, totals) } } rescue ::Wurk::Metrics::Query::WindowTooWide => e render json: { error: e. }, status: :bad_request end |
#metrics_for_job ⇒ Object
116 117 118 119 120 121 122 123 124 |
# File 'app/controllers/wurk/api_controller.rb', line 116 def metrics_for_job klass = params[:klass].to_s minutes, hours = metrics_window(params) rows = ::Wurk::Web::Enterprise::Historical.for_job(klass, minutes: minutes, hours: hours) series = rows.map { |row| row.merge(at: row[:at].to_f) } render json: { klass: klass, minutes: minutes, hours: hours, series: series } rescue ::ArgumentError, ::Wurk::Metrics::Query::WindowTooWide => e render json: { error: e. }, status: :bad_request end |
#pause_cron ⇒ Object
94 |
# File 'app/controllers/wurk/api_controller.rb', line 94 def pause_cron = render_cron_action(::Wurk::Web::Enterprise::Periodic.pause(params[:lid].to_s)) |
#processes ⇒ Object
58 59 60 |
# File 'app/controllers/wurk/api_controller.rb', line 58 def processes render json: ::Wurk::ProcessSet.new.map { |p| ::Wurk::Api::Serializers.process_row(p) } end |
#queue ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'app/controllers/wurk/api_controller.rb', line 44 def queue q = ::Wurk::Queue.new(params[:name].to_s) page = ::Wurk::Api::Pagination.window(params) jobs = ::Wurk::Api::Pagination.slice(q, page) { |rec| ::Wurk::Api::Serializers.job_record(rec) } render json: { name: q.name, size: q.size, latency: q.latency, paused: q.paused?, page: page[:page], count: page[:count], jobs: jobs } end |
#queues ⇒ Object
40 41 42 |
# File 'app/controllers/wurk/api_controller.rb', line 40 def queues render json: ::Wurk::Stats.new.queue_summaries.map { |q| ::Wurk::Api::Serializers.queue_summary(q) } end |
#reset_limiter ⇒ Object
84 85 86 87 |
# File 'app/controllers/wurk/api_controller.rb', line 84 def reset_limiter ::Wurk::Web::Enterprise::Limits.reset(params[:name].to_s) render json: { ok: true } end |
#retries ⇒ Object
54 |
# File 'app/controllers/wurk/api_controller.rb', line 54 def retries = render_sorted_set(::Wurk::RetrySet.new) |
#scheduled ⇒ Object
55 |
# File 'app/controllers/wurk/api_controller.rb', line 55 def scheduled = render_sorted_set(::Wurk::ScheduledSet.new) |
#search ⇒ Object
137 138 139 140 141 142 143 |
# File 'app/controllers/wurk/api_controller.rb', line 137 def search substr = params[:substr].to_s return render(json: { substr: substr, total: 0, hits: [] }) if substr.empty? hits = ::Wurk::Web::Search.new(substr, kinds: parse_search_kinds(params), limit: parse_search_limit(params)).to_a render json: { substr: substr, total: hits.size, hits: hits } end |
#stats ⇒ Object
36 37 38 |
# File 'app/controllers/wurk/api_controller.rb', line 36 def stats render json: ::Wurk::Api::Serializers.stats_payload(::Wurk::Stats.new) end |
#stream ⇒ Object
SSE: one ‘event: stats` per tick with a fresh Stats snapshot. Caps at `STREAM_MAX_DURATION` so a stale browser tab can’t tie a Rails worker forever — the client reconnects automatically when the stream closes.
‘?max_duration=` and `?tick=` are test/debug knobs; the SPA never sets them. `?max_duration=0` emits one tick and closes.
151 152 153 154 155 156 157 158 |
# File 'app/controllers/wurk/api_controller.rb', line 151 def stream stream_headers! clamp = ::Wurk::Api::Pagination.method(:clamp_float) tick = clamp.call(params[:tick], 0.0, STREAM_TICK_SECONDS, STREAM_TICK_SECONDS) max_dur = clamp.call(params[:max_duration], 0.0, STREAM_MAX_DURATION, STREAM_MAX_DURATION) sse = ::ActionController::Live::SSE.new(response.stream, retry: (STREAM_TICK_SECONDS * 1000).to_i) drive_stream(sse, tick, max_dur) end |
#unpause_cron ⇒ Object
95 |
# File 'app/controllers/wurk/api_controller.rb', line 95 def unpause_cron = render_cron_action(::Wurk::Web::Enterprise::Periodic.unpause(params[:lid].to_s)) |