Skip to content
GantryCD

Notifications

GantryCD tells your other systems when deployments run. Notification integrations are per-organization configurations that subscribe to deployment-execution events and deliver a message to a provider — Slack today, more later.

ProviderWhat you configureHow it’s picked up
SlackA bot token (your own Slack App install) + a default channelEach matching org integration receives a chat.postMessage per subscribed event.
WebhookAn HTTP(S) URL, optional signing secret + headersEach matching org integration receives a signed JSON POST per subscribed event.

The model

  • Per organization. Every org defines its own integrations and supplies its own credentials (e.g. its own Slack bot token). There is no operator-level, shared token — the provider code is built into the backend, but the secrets belong to each org and are encrypted at rest.

  • Event subscriptions. An integration lists the events it wants. The first family concerns deployments — plan, destroy, refresh and raw executions that take the stack’s lane. Pull-request previews and local plans are not deployments; they have their own family below.

    EventFires when
    deployment_succeededA deployment finished.
    deployment_failedA deployment failed.
    deployment_cancelledA deployment was cancelled.
    deployment_auto_skippedThe stack’s queue policy skipped a deployment on its own — superseded by a newer one, or aged out waiting for confirmation or a free lane. A skip you perform stays silent.
    deployment_awaiting_confirmationA deployment has run its plan and is waiting for someone to approve the apply.
    run_command_executedSomeone ran an arbitrary command against a stack. That runs code on a runner holding the stack’s cloud credentials, so it is worth watching. The message reports the command’s size, never its text — commands often contain secrets.
    pull_request_promotedSomeone promoted a pull request’s plan to a real deployment.
    dependent_trigger_failedAn apply succeeded and should have auto-deployed a stack that depends on it, but could not (the dependent was deleted, is unsynced, failed a preflight check, …). Without this the broken automation is only visible on the parent deployment’s page.

    Previews. A preview is a read-only plan that never takes the stack’s lane: every push to an open pull request produces one, and so does a local plan. They mirror the deployment events one for one, and are separate so that subscribing to deployment outcomes does not drown you in one message per push.

    EventFires when
    preview_succeededA preview’s plan finished.
    preview_failedA preview’s plan failed.
    preview_cancelledA preview was cancelled.
    preview_auto_skippedA preview waiting for confirmation aged out under the stack’s confirmation timeout. The routine retirements — superseded by a newer push, retracted because the stack’s plan requirements stopped being met, or the pull request closed — stay silent: they are the pull request moving on, not something to act on.
    preview_awaiting_confirmationA pull-request preview is waiting for someone to allow its plan to run — the manual setting of a stack’s pull-request plan mode. Expect one per push to every open pull request on such a stack.

    deployment_awaiting_confirmation and preview_awaiting_confirmation are the two events that ask you to do something rather than telling you what happened.

    Stack lifecycle. Unlike the deployment events these are caused by a person or a service account, and the payload says who.

    EventFires when
    stack_createdA stack was created.
    stack_deletedA stack was deleted.
    stack_renamedA stack was renamed. Renaming mints a new stack ID, so the payload carries the old one too — otherwise there is nothing connecting the two.
    stack_syncedA stack was pointed at a new commit. Re-syncing a stack that is already on that commit is silent.

    Repository sync.

    EventFires when
    scm_sync_failedAn inbound event from a repository ran out of retries and was given up on. This means GantryCD has quietly stopped reacting to that repository — pushes and pull requests there are no longer producing deployments. Rare, and worth acting on.

    This one is about a repository, not a stack, so an integration with a stack-label selector will not receive it: a selector says “only these stacks”, and this event concerns none in particular.

    Dependency diagnostics.

    EventFires when
    explore_findings_changedOn a schedule you choose, reporting how many dependency cycles, orphan references and duplicate resources your organization currently has.

    You set the schedule as a cron-style expression in UTC — minute hour * * day-of-week:

    ExpressionRuns
    0 10 * * 1Mondays at 10:00 UTC
    0 9 * * *Every day at 09:00 UTC
    30 8 * * 1-5Weekdays at 08:30 UTC

    Day-of-week is 0-6 with 0 = Sunday, and accepts lists and ranges. The minute and hour must be single values, and day-of-month and month must both be * — the report runs at most once a day, so there is no way to write an hourly one. Expect the report within about fifteen minutes of the time you set: a background job delivers it, and it does not run continuously.

    This one is a standing report, not an alert. These findings are a backlog to work through rather than incidents to react to, so it arrives on a rhythm you can build a habit around and tells you what is outstanding whether or not it changed since last time. Each report also shows the movement since the previous one, so you can see whether you are getting on top of it.

    It reports counts, not individual findings: the sweep behind it recomputes everything from scratch each hour and keeps no history, so “which cycle is new” is a question the data cannot answer.

    An organization with nothing to report is skipped, so a clean one stays quiet rather than sending an empty message every week. Nothing is recorded as sent in that case, so when something does appear it is reported at the next scheduled time rather than that occurrence being treated as already used up.

    When an organization’s dependency graph is too large to analyse, cycles and orphans are not checked at all. The report says so rather than reporting them as zero.

    There is no stack_updated. “Updated” covers environment variables, labels, contexts and protected keys, each edited separately — it would be the noisiest event here and say the least.

  • Only when something changed. An integration can set changes only, which drops a deployment notification when its plan ran and reported nothing to do. Deployments whose plan could not be measured are still delivered — the filter stays quiet only when it can prove there was nothing to say.

  • Stack-label routing. An integration can carry a stack-label selector (only notify for stacks whose labels match) and provider-specific routing keyed on labels (for Slack, a stack label can choose the channel). See Slack.

Checking it works

Every integration has a Test action, and it sends a message shaped like the event the integration subscribes to — not always a deployment. If you subscribe to several, it uses the first in the list above; add ?event_type= to the test request to pick another.

Worth doing once per provider after you set one up, because a message that a provider rejects (a channel the bot is not in, a payload it will not render) fails at send time, not when you save the configuration. A test that fails tells you immediately; a real event that fails becomes a dead-lettered delivery you have to go and look for.

These are the ones worth eyeballing, because each renders differently:

Send a test forCheck that
deployment_succeededThe change counts appear, and read as counts rather than as +0 ~0 -0.
deployment_awaiting_confirmationThe button says to confirm, and the link opens the deployment.
run_command_executedThe command’s size appears and its text does not.
stack_renamedBoth the old and new names appear.
scm_sync_failedThe repository is named and the message leads with the consequence.
explore_findings_changedThe counts appear and the link opens Insights.

Always asynchronous, always retried

Notifications never run on the deployment’s critical path. When a deployment finishes, GantryCD writes a durable delivery row and a background worker sends it:

  • A Postgres LISTEN/NOTIFY wake delivers within moments; a one-minute scheduler sweep is the safety net if a wake is missed.
  • Each delivery is retried with backoff up to a fixed maximum, then dead-lettered (kept, not silently dropped) so a failing endpoint is visible rather than lost.
  • A notification failure never blocks or fails a deployment.
  • Every terminal deployment is covered — including failures surfaced by self-heal jobs — via a reconcile sweep, not just the fast path.
  • Deliveries that have not gone out — in flight, retrying, or dead-lettered — are viewable at GET /api/v1/orgs/{org_id}/notification-deliveries, and a dead-lettered one can be re-sent with POST .../notification-deliveries/{delivery_id}/retry. Successful deliveries are not recorded — the row is deleted once the message goes out — so that list being empty means nothing is currently failing. It is not proof that everything was delivered: dead rows are pruned after GANTRYCD_NOTIFICATION_DELIVERY_RETENTION, so an old failure eventually leaves the list.

For the internals — the provider interface, the outbox, retry/dead-letter, and the deployment hook — see Notifications internals.