Module: RoundhouseUi::JobSetBrowsing
- Extended by:
- ActiveSupport::Concern
- Included in:
- DeadController, RetriesController, ScheduledController
- Defined in:
- app/controllers/concerns/roundhouse_ui/job_set_browsing.rb
Overview
Shared search + pagination over a Sidekiq job set (dead, retry, scheduled). Keeps the controllers from duplicating the scan/filter/window logic.
Constant Summary collapse
- PER_PAGE =
25- BULK_CAP =
safety ceiling on a single match-set action
1_000
Instance Method Summary collapse
- #browse(set, query, page, per = PER_PAGE, tag: nil) ⇒ Object
-
#bulk_apply(set, query, op, cap = BULK_CAP, tag: nil) ⇒ Object
Apply an op ("retry"/"delete") to every entry matching the query, capped at BULK_CAP.
-
#entry_matches?(entry, query, tags = Tags::EMPTY) ⇒ Boolean
Tag values are part of the haystack, so typing a squad name finds its jobs without reaching for the structured filter.
-
#entry_selected?(entry, query, tag, cache) ⇒ Boolean
Both the browse and bulk paths run every candidate through this, so the rows an operator sees are exactly the rows a bulk action will touch — including when a tag value is what matched the free-text search.
- #entry_tagged?(tags, key, value) ⇒ Boolean
- #entry_tags(entry, cache) ⇒ Object
-
#queue_filter ⇒ Object
?queue=name— exact match, so clicking a queue pill or picking one from the palette narrows to that queue. -
#tag_cache_for(_tag) ⇒ Object
Shares the request memo with TagsHelper — controller ivars carry into the view, so an entry resolved while scanning is not resolved again when its badge renders.
-
#tag_filter ⇒ Object
Returns [entries_for_page, has_next?].
Instance Method Details
#browse(set, query, page, per = PER_PAGE, tag: nil) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 24 def browse(set, query, page, per = PER_PAGE, tag: nil) start = (page - 1) * per jobs = [] has_next = false matched = 0 cache = tag_cache_for(tag) set.each do |entry| next unless entry_selected?(entry, query, tag, cache) if matched < start matched += 1 elsif jobs.size < per jobs << entry matched += 1 else has_next = true break end end [ jobs, has_next ] end |
#bulk_apply(set, query, op, cap = BULK_CAP, tag: nil) ⇒ Object
Apply an op ("retry"/"delete") to every entry matching the query, capped at BULK_CAP. Entries are collected first, then acted on — mutating a Sidekiq set mid-iteration skips entries. Returns [count_acted_on, capped?].
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 51 def bulk_apply(set, query, op, cap = BULK_CAP, tag: nil) matches = [] capped = false cache = tag_cache_for(tag) set.each do |entry| next unless entry_selected?(entry, query, tag, cache) matches << entry if matches.size >= cap capped = true break end end matches.each { |entry| op == "delete" ? entry.delete : entry.retry } [ matches.size, capped ] end |
#entry_matches?(entry, query, tags = Tags::EMPTY) ⇒ Boolean
Tag values are part of the haystack, so typing a squad name finds its jobs without reaching for the structured filter. Safe to widen here only because browse and bulk_apply share this predicate — if they diverged, a search would show one set of rows and "delete all matching" would act on another.
116 117 118 119 120 121 122 123 124 125 126 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 116 def entry_matches?(entry, query, = Tags::EMPTY) needle = query.downcase # Queue matches on equality, not substring: typing a queue name should # find its jobs, but this predicate also drives bulk_apply, so "default" # must never additionally select "default_low". return true if entry.queue.to_s.downcase == needle [ entry.klass, entry.jid, entry.item["error_class"], entry.item["error_message"], entry.args.to_s, *.values ] .any? { |hay| hay.to_s.downcase.include?(needle) } end |
#entry_selected?(entry, query, tag, cache) ⇒ Boolean
Both the browse and bulk paths run every candidate through this, so the rows an operator sees are exactly the rows a bulk action will touch — including when a tag value is what matched the free-text search.
71 72 73 74 75 76 77 78 79 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 71 def entry_selected?(entry, query, tag, cache) return false if @queue_filter.present? && entry.queue.to_s != @queue_filter = (entry, cache) return false if query.present? && !entry_matches?(entry, query, ) return true if tag.nil? entry_tagged?(, tag) end |
#entry_tagged?(tags, key, value) ⇒ Boolean
89 90 91 92 93 94 95 96 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 89 def entry_tagged?(, (key, value)) # A declared vocabulary is authoritative: filtering on a key the host # never declared matches nothing rather than everything. declared = Tags.filters return false if declared && !declared.key?(key) Tags.match?(, key, value) end |
#entry_tags(entry, cache) ⇒ Object
98 99 100 101 102 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 98 def (entry, cache) return Tags::EMPTY unless RoundhouseUi. Tags.for(klass: entry.klass, item: entry.item, cache: cache) end |
#queue_filter ⇒ Object
?queue=name — exact match, so clicking a queue pill or picking one from
the palette narrows to that queue. Exact rather than substring because
this feeds bulk_apply too, and "default" must never also select
"default_low".
85 86 87 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 85 def queue_filter params[:queue].to_s.strip.presence end |
#tag_cache_for(_tag) ⇒ Object
Shares the request memo with TagsHelper — controller ivars carry into the view, so an entry resolved while scanning is not resolved again when its badge renders. Tags.for picks the key: class name normally, jid in per-job mode.
108 109 110 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 108 def tag_cache_for(_tag) @rh_tag_cache ||= {} end |
#tag_filter ⇒ Object
Returns [entries_for_page, has_next?]. Scans only far enough to fill the
requested page plus one (to know if a next page exists) — never loads the
whole set, so a 50k dead set stays cheap to page through.
?tag=key:value — an exact match against a host-defined tag (ADR 0002),
parsed once per request. Deliberately structured rather than folded into
the free-text query: substring search feeding bulk_apply would silently
widen destructive bulk actions.
17 18 19 20 21 22 |
# File 'app/controllers/concerns/roundhouse_ui/job_set_browsing.rb', line 17 def tag_filter key, value = params[:tag].to_s.split(":", 2) return nil if key.blank? || value.blank? [ key, value ] end |