Files
windmill/backend/windmill-queue
Ruben Fiszel 717e38a0c6 feat: let a workspace fall back to the instance critical alert channels (#10292)
* feat(alerts): let a workspace fall back to the instance critical alert channels

A workspace with no error handler had no way to surface failed jobs, and the
instance critical alert channels a superadmin already configured (Slack, Teams,
email) were unreachable from a workspace: the workspace Slack error handler
posts with the workspace's own bot token, not the instance one.

Adds an opt-in workspace setting that reports failed jobs to those channels
when, and only when, no workspace error handler is configured. The report is
send-only: it skips the `alerts` table so workspace job failures never flood the
instance-wide feed superadmins triage.

Rejected on cloud (the channels belong to the instance operator, who is not the
tenant) and on fork workspaces (throwaway copies of a parent's runnables).
Settable from workspace settings and from the new-workspace screen.

The opt-in and the existing `mute_critical_alerts` flag are folded into the
query already behind WORKSPACE_ERROR_HANDLER_CACHE, so a failed job costs no
extra round trip, and workspaces with neither a handler nor the opt-in return
before the per-runnable mute lookup.

* chore(sqlx): add offline query cache entries for the new settings queries

* refactor(alerts): make instance alerts a destination tab and address review

Instance alerts are a fifth error-handler destination rather than a separate
toggle: the backend already treats them as mutually exclusive with a handler
script, so one "where do failures go?" control matches the semantics and drops
the inert-while-a-handler-is-set state. The tab is offered on the workspace
error handler only, not on schedules or triggers.

Review fixes:
- the fork boundary is enforced at dispatch (join on parent_workspace_id), so a
  workspace attached as a fork/dev after opting in stops reporting; attaching
  also clears the stored flag, and the settings page never selects a tab it does
  not render, which would have submitted a value the API rejects on a fork
- mute_critical_alerts no longer gates this path: it is the UI-feed mute, and
  this path writes no feed entry
- cancellations are not reported: they are a human action, and this destination
  has no per-workspace mute of its own
- per-workspace throttle with a rollup count, so a flapping runnable cannot turn
  into unbounded Slack/SMTP traffic on channels shared by the whole instance
- log the dispatch, audit the flag, name the columns in the rename INSERT, drop
  the generated migration placeholders

* chore(alerts): state the fork/cloud invariant on canUseInstanceAlerts

* chore(sqlx): cache the attach_dev_workspace settings update
2026-07-24 09:58:27 +02:00
..