diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bd95f6..476f8ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Slow job webhook alert — fires when the number of currently-claimed jobs exceeding `slow_job_threshold` reaches `alert_slow_job_count_threshold`; respects the shared `alert_webhook_url` and `alert_webhook_cooldown` settings; payload includes `type: "slow_jobs"`, `count`, and `threshold` - Stale process webhook alert — fires when the number of workers with a heartbeat older than 5 minutes meets `alert_stale_process_threshold`; reuses the shared webhook URL and cooldown; payload includes `type: "stale_processes"`, `count`, and `threshold` +- Job wait time column — shows how long a claimed job waited in the queue before being picked up (time from `enqueued_at` to claim time); displayed on the claimed tab only; also included as `wait_time_seconds` in CSV exports ## [1.2.0] - 2026-05-27 diff --git a/ROADMAP.md b/ROADMAP.md index f6f0079..29f5a45 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,14 +5,6 @@ --- -## v1.3 — Alerting Depth - -> _More signals, fewer blind spots._ - -- **Job wait time column** — show time from `enqueued_at` to `created_at` on claimed executions; a direct measure of queue SLA (how long jobs waited before a worker picked them up) - ---- - ## v1.4 — Audit & Compliance > _Requires an opt-in migration — kept separate from the no-migration-required releases above._ diff --git a/app/controllers/solid_stack_web/jobs_controller.rb b/app/controllers/solid_stack_web/jobs_controller.rb index b443190..b250ff1 100644 --- a/app/controllers/solid_stack_web/jobs_controller.rb +++ b/app/controllers/solid_stack_web/jobs_controller.rb @@ -82,10 +82,14 @@ def require_discardable def jobs_csv CSV.generate(headers: true) do |csv| - csv << %w[id class_name queue_name status priority enqueued_at] + headers = %w[id class_name queue_name status priority enqueued_at] + headers << "wait_time_seconds" if @status == "claimed" + csv << headers filtered_scope.each do |execution| job = execution.job - csv << [job.id, job.class_name, job.queue_name, @status, job.priority, job.created_at.iso8601] + row = [job.id, job.class_name, job.queue_name, @status, job.priority, job.created_at.iso8601] + row << (execution.created_at - job.created_at).to_i if @status == "claimed" + csv << row end end end diff --git a/app/views/solid_stack_web/jobs/index.html.erb b/app/views/solid_stack_web/jobs/index.html.erb index dcca7c0..90ffe46 100644 --- a/app/views/solid_stack_web/jobs/index.html.erb +++ b/app/views/solid_stack_web/jobs/index.html.erb @@ -112,6 +112,7 @@ <%= sort_header_th("Priority", "priority", sort_url, current_sort: @sort, current_dir: @direction) %> <%= sort_header_th("Enqueued At", "created_at", sort_url, current_sort: @sort, current_dir: @direction) %> <% if @status == "scheduled" %>