Skip to content

Owners page: map failed jobs to their CODEOWNERS teams - #20

Open
ryanmrodriguez wants to merge 1 commit into
cmer:mainfrom
ryanmrodriguez:20261105-failures-by-owner
Open

ryanmrodriguez wants to merge 1 commit into
cmer:mainfrom
ryanmrodriguez:20261105-failures-by-owner

Conversation

@ryanmrodriguez

Copy link
Copy Markdown

Problem

When a queue is shared by many teams, the Failed list can't answer "which of these are mine?". Resque setups often solve this with a code owners view. Flightdeck has nothing like it.

Change

An Owners page listing failed jobs per class, with each class's owners and counts for the last 1h, 3h, 24h, 3d and 7d. It's off by default, with one setting to turn it on:

Flightdeck.configure do |config|
  config.codeowners_path = ".github/CODEOWNERS"
end

Until that's set there's no sidebar link, and /owners shows a short setup message.

  • Owners come from the host's CODEOWNERS file, following GitHub's rules: the last match wins, and a rule with no owners clears ownership. Each class is matched by the file that defines it rather than a naming convention, so components and engines resolve like any other path.
  • Unowned: a class that can't be loaded, or is defined outside the repo (ActionMailer::MailDeliveryJob), shows as Unowned.
  • Filtering: owner chips and a case-insensitive class search. Both work in Ruby, since every class is already in memory, so they add no query.
  • Links: class names and counts open the Failed list, filtered by class and time window.

failed_within

The links need a new failed_within filter on JobsQuery. It's carried in list_filters, so pagination, tabs, polling and "Retry/Discard all matching" all see the same rows. Only failed jobs can have failed recently, so with a window on, All matches Failed and the other tabs show 0.

This changes which rows the bulk actions select, so it's the part most worth reviewing. A single-row discard still ignores list filters, as it already does for class and queue.

The Filter button also used to drop an active class_name. It now keeps it, and the jobs page shows the class and window as chips.

Worth knowing

  • Still failed, not a history: Solid Queue deletes a failed execution on retry or discard, so a window counts jobs that failed in it and are still failed. The page says so.
  • Loading classes: finding a class's file means resolving the constant. This never touches job arguments, and a class that fails to load shows as Unowned rather than breaking the page.
  • Deploys: CODEOWNERS has to be present where the dashboard runs, and many images leave out .github. If it's missing, the page says so.
  • Cost: the page runs one grouped query over failed_executions, which has no created_at index. It's cached for chart_cache_ttl, and the page polls at the chart interval.
  • Overlap with Fuzzy job class search and queue filter #19: both change apply_filters in jobs_query.rb, so whichever merges second needs a small conflict fix. Class search on the Failed list is currently a prefix match, so the Total row stops linking during a search, because the same search there could show something different.

Testing

  • bin/test passes: 339 tests in both host modes, on SQLite. Rubocop and the asset check are clean.
  • Bulk retry and discard have tests proving they leave jobs outside the window alone. Those tests fail if the window is dropped from list_filters.
  • CODEOWNERS matching is covered for anchoring, *, **, ?, dir/*, escapes and last-match overrides.
  • bin/demo seeds a sample CODEOWNERS and overlapping job classes, so the page can be tried by hand. These live in test/dummy and don't ship in the gem.
  • Not yet run: PostgreSQL and MySQL, which need CI here. The new SQL is plain SUM(CASE WHEN ...) and has no adapter-specific code. The page was checked with HTTP requests against the demo, not in a real browser, and the system tests weren't run.

Add an Owners page listing failed jobs per class, with the owners of each
class and counts for the last 1h, 3h, 24h, 3d and 7d. It's off until
config.codeowners_path is set, so existing installs see no change.

Each class is matched by the file that defines it rather than a naming
convention, so components and engines resolve like any other path. A class
that can't be loaded or lives outside the repo shows as Unowned.

Class names and counts open the Failed list filtered by class and window.
That needs a new failed_within filter on JobsQuery. It travels in
list_filters, so pagination, tabs, polling and "all matching" bulk actions
all see the same rows. The Filter button also now keeps a class filter, and
the jobs page shows the class and window it's filtered by.

Owner chips and a class search narrow the page in Ruby, since every class is
already in memory. Counts only cover jobs that are still failed: Solid Queue
deletes a failed execution when its job is retried or discarded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant