Module: Wurk::Api::Serializers
- Defined in:
- app/controllers/wurk/api/serializers.rb
Overview
Pure mapping from inspector objects → JSON-shaped Hashes for the dashboard SPA. Keeping the serializers out of the controller lets the action methods stay tiny and lets future endpoints share the same field shapes without re-implementing them.
Class Method Summary collapse
- .cron_row(loop_obj, now_epoch) ⇒ Object
-
.history_point(row) ⇒ Object
One point in a cluster-total time-series (Wurk::Metrics::Query.history).
-
.job_record(record) ⇒ Object
Host-registered custom job-info rows (spec §25.2) ride along as ‘custom_rows` for the SPA’s job-detail modal (see Config#job_info_pairs, which gates on registration so the common no-extension case is free).
- .limiter_row(name, meta) ⇒ Object
-
.limiter_status(name, meta) ⇒ Object
Reconstruct the limiter (read-only, ‘register: false`) just to read its uniform `{ used, limit, reset_at, available? }` status for the Limits tab.
- .metric_row(klass, totals) ⇒ Object
- .parse_options(raw) ⇒ Object
- .process_row(process) ⇒ Object
-
.profile_record(rec) ⇒ Object
One profile row for the Profiles pane.
-
.queue_history_series(row) ⇒ Object
One queue’s size/latency gauge series (Wurk::Metrics::Query.queue_history).
- .queue_summary(summary) ⇒ Object
- .sorted_entry(entry) ⇒ Object
-
.stats_payload(stats) ⇒ Object
Wire-shape consumed by the React dashboard’s landing page + SSE feed.
-
.work_row(process_id, thread_id, work) ⇒ Object
One in-flight job (WorkSet row) for the Busy page’s process detail.
Class Method Details
.cron_row(loop_obj, now_epoch) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/controllers/wurk/api/serializers.rb', line 124 def cron_row(loop_obj, now_epoch) { lid: loop_obj.lid, schedule: loop_obj.schedule, klass: loop_obj.klass, queue: loop_obj.queue, tz: loop_obj.tz_name, paused: loop_obj.paused?, args: loop_obj.args, last_fire_at: loop_obj.last_fired_at, next_fire_at: loop_obj.next_fire_at(now_epoch) } end |
.history_point(row) ⇒ Object
One point in a cluster-total time-series (Wurk::Metrics::Query.history). ‘at` is epoch seconds at the bucket start.
144 145 146 |
# File 'app/controllers/wurk/api/serializers.rb', line 144 def history_point(row) { at: row[:at], processed: row[:p], failed: row[:f], runtime_ms: row[:ms] } end |
.job_record(record) ⇒ Object
Host-registered custom job-info rows (spec §25.2) ride along as ‘custom_rows` for the SPA’s job-detail modal (see Config#job_info_pairs, which gates on registration so the common no-extension case is free). Divergence: wurk evaluates these during job-list serialization — the SPA renders job detail client-side — not in a dedicated server detail view.
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'app/controllers/wurk/api/serializers.rb', line 42 def job_record(record) base = { jid: record.jid, klass: record.display_class, args: record.display_args, queue: record.queue, enqueued_at: record.enqueued_at&.to_f, created_at: record.created_at&.to_f } rows = ::Wurk::Web.config.job_info_pairs(record) rows.empty? ? base : base.merge(custom_rows: rows) end |
.limiter_row(name, meta) ⇒ Object
103 104 105 106 107 108 109 110 111 |
# File 'app/controllers/wurk/api/serializers.rb', line 103 def limiter_row(name, ) { name: name, type: ['type'].to_s, fingerprint: ['fingerprint'].to_s, options: (['options']), status: limiter_status(name, ) } end |
.limiter_status(name, meta) ⇒ Object
Reconstruct the limiter (read-only, ‘register: false`) just to read its uniform `{ used, limit, reset_at, available? }` status for the Limits tab. Best-effort: a malformed meta hash yields nil rather than 500-ing the whole list.
117 118 119 120 121 122 |
# File 'app/controllers/wurk/api/serializers.rb', line 117 def limiter_status(name, ) limiter = ::Wurk::Limiter.build(name, ['type'], (['options'])) limiter&.status rescue StandardError nil end |
.metric_row(klass, totals) ⇒ Object
138 139 140 |
# File 'app/controllers/wurk/api/serializers.rb', line 138 def metric_row(klass, totals) { klass: klass, processed: totals[:p], failed: totals[:f], runtime_ms: totals[:ms] } end |
.parse_options(raw) ⇒ Object
155 156 157 158 159 160 161 |
# File 'app/controllers/wurk/api/serializers.rb', line 155 def (raw) return {} if raw.nil? || raw.to_s.empty? ::JSON.parse(raw) rescue ::JSON::ParserError {} end |
.process_row(process) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'app/controllers/wurk/api/serializers.rb', line 66 def process_row(process) { identity: process.identity, hostname: process['hostname'], pid: process['pid'], tag: process.tag, concurrency: process['concurrency'], busy: process['busy'], beat: process['beat'], quiet: process.stopping?, rss: process['rss'], rtt_us: process['rtt_us'], started_at: process['started_at'], cpu_model: process['cpu_model'], cores: process['cores'], memory_total_kb: process['memory_total_kb'], labels: process.labels, queues: process.queues, version: process.version, embedded: process. } end |
.profile_record(rec) ⇒ Object
One profile row for the Profiles pane. ‘key` drives the view/data links.
164 165 166 167 168 169 170 171 172 173 174 |
# File 'app/controllers/wurk/api/serializers.rb', line 164 def profile_record(rec) { key: rec.key, jid: rec.jid, token: rec.token, type: rec.type, size: rec.size, elapsed: rec.elapsed, started_at: rec.started_at&.to_i } end |
.queue_history_series(row) ⇒ Object
One queue’s size/latency gauge series (Wurk::Metrics::Query.queue_history). ‘points` are oldest→newest; `at` is epoch seconds at the bucket start, `size` is queue depth, `latency` is head-of-line wait in seconds.
151 152 153 |
# File 'app/controllers/wurk/api/serializers.rb', line 151 def queue_history_series(row) { name: row[:name], points: row[:points].map { |p| { at: p[:at], size: p[:size], latency: p[:latency] } } } end |
.queue_summary(summary) ⇒ Object
33 34 35 |
# File 'app/controllers/wurk/api/serializers.rb', line 33 def queue_summary(summary) { name: summary.name, size: summary.size, latency: summary.latency, paused: summary.paused? } end |
.sorted_entry(entry) ⇒ Object
55 56 57 58 59 60 61 62 63 64 |
# File 'app/controllers/wurk/api/serializers.rb', line 55 def sorted_entry(entry) job_record(entry).merge( score: entry.score, at: entry.at.to_f, error_class: entry['error_class'], error_message: entry['error_message'], retry_count: entry['retry_count'], error_backtrace: entry.error_backtrace ) end |
.stats_payload(stats) ⇒ Object
Wire-shape consumed by the React dashboard’s landing page + SSE feed. Field names match the SPA’s ‘StatsSnapshot` interface in frontend/src/hooks/useSSE.ts — keep them in sync. The canonical Sidekiq-compatible accessors on Wurk::Stats use `_size` suffixes; this serializer renames them for the dashboard’s wire shape only.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'app/controllers/wurk/api/serializers.rb', line 17 def stats_payload(stats) { processed: stats.processed, failed: stats.failed, expired: stats.expired, enqueued: stats.enqueued, busy: stats.workers_size, scheduled: stats.scheduled_size, retries: stats.retry_size, dead: stats.dead_size, processes: stats.processes_size, latency: stats.default_queue_latency, queues: stats.queue_summaries.map { |q| queue_summary(q) } } end |
.work_row(process_id, thread_id, work) ⇒ Object
One in-flight job (WorkSet row) for the Busy page’s process detail.
90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'app/controllers/wurk/api/serializers.rb', line 90 def work_row(process_id, thread_id, work) record = work.job { process_id: process_id, thread_id: thread_id, queue: work.queue, klass: record.display_class, args: record.display_args, jid: record.jid, run_at: work.run_at.to_f } end |