Clean up the Fly.io preview apps your team left behind

By General Input

See every leftover pull request preview app on Fly.io next to the pull request that created it, and retire the dead ones safely.

Integrations

  • Fly.io
  • GitHub

Type

App

Categories

  • Engineering
  • Operations

Build me an app for governing the Fly.io preview environments my team leaves behind. Every pull request spins up a review app named something like pr-123-my-org-my-repo, and cleanup depends on a GitHub Action firing when the pull request closes, which misses often enough that we pay for dead environments for months. I want one screen that shows every leftover review app, ranked worst first, with the actions to retire it safely.

The main screen is a board of my Fly.io apps. Use List Apps, filtered to my organization slug, and keep only the apps whose names match a review app naming pattern. That pattern is a setting, defaulting to pr-{number}-{repo_org}-{repo_name}, and parsing it yields the pull request number and the repository for each app. Teams name review apps differently, so let me edit the pattern in settings and show a live preview of which of my current app names match before I save it.

Each row joins the Fly app to its GitHub pull request. Resolve the pull request with Search Issues and Pull Requests, scoped to the repository and number parsed out of the app name, then call Get a Pull Request for the authoritative details: number, title, whether it is open, merged or closed, who opened it, and when it was merged or closed. When several apps come from the same repository, List Pull Requests is a cheaper way to pull that repository's recent pull requests in one call instead of one lookup per row. Show the pull request number and title as a link, its state, the author, and how long ago it closed.

For each app also show how old it is, how many Machines it has and how many of those are actually running, using List Machines for each Machine's state, region and created time, and which volumes are still attached, using List Volumes for size, region, whether the volume is attached to a Machine, and created time. If the app record carries no creation timestamp, derive the app age from its oldest Machine. Keep Machines and volumes in separate columns: a volume keeps billing by the hour whether or not its Machine is running, so an app with zero running Machines and two live volumes is still costing money and must never look clean.

Rank rows so the worst offenders float to the top, meaning apps whose pull request was merged or closed more than a chosen number of days ago, a setting defaulting to seven, but which still have running Machines or live volumes. Sort by how much is still live and how long it has been dead: running Machine count, total volume size, and days since the pull request closed. Give each row a clear badge such as Stale, Watch or Active, and let me filter to just the flagged rows, filter by repository, and search by app name.

Every row gets actions: Stop Machine for a single Machine or for every running Machine on the app, Create Snapshot for a volume, Destroy Volume, and Destroy App. Stopping is a single click with a clear result toast. Anything destructive sits behind a confirmation dialog that names exactly what is about to disappear, the app and its Machines and its volumes, and requires typing the app name to proceed. That dialog carries a snapshot volumes first checkbox which runs Create Snapshot on each volume before the destroy runs. Snapshots are not instant, so show the snapshot as pending and let me re-check it with List Snapshots rather than pretending it finished. The confirmation should also warn that managed add ons attached to an app are not necessarily removed when the app is deleted and are worth checking separately.

Add a Review stale environments button that starts a background agent across every flagged app. For each one the agent checks the pull request state with Get a Pull Request, looks at the Machine's recent activity with List Events, and reviews the volumes and any existing snapshots with List Volumes and List Snapshots, then writes a per app recommendation of destroy, keep, or ask the owner, with a one line reason such as merged 24 days ago, no Machine events since, two volumes still live. Write those recommendations back into the app so each row shows the verdict, the reason and when it was generated, and show progress while the agent works. The agent itself never deletes anything. A human reads the recommendations and approves the sweep, so also let me select the rows recommended for destroy and run those destroys as a batch, still behind the same confirmation.

Persist a few things in the app: the naming pattern, the organization slug, the staleness threshold in days and the default for snapshot before destroy; the latest agent recommendation per app; a keep until snooze so an environment I have deliberately spared drops off the flagged list until that date, along with the reason and who set it; and an action log recording every stop, snapshot and destroy with who did it and when, so the sweep is auditable afterwards.

Two practical notes. Fly's API is rate limited to roughly one request per second per action and GitHub search allows about thirty requests a minute, so load the board in batches, cache what you fetch for the session, render rows as they resolve instead of blocking on the whole set, and let me refresh a single row on demand. And handle the ordinary messy cases: an app whose name matches the pattern but has no matching pull request should appear as unmatched rather than silently disappear, a repository I cannot see should say so, an app with no Machines at all should still show its volumes, and a destroy that fails because a volume is still attached should tell me exactly that.

Related prompts

Explore more prompts
Open a Heroku release war room the moment production looks wrongSee what Hacker News really thinks of the tools in your stackSee and fix Terraform variable drift across every workspaceA docs coverage board that catches what shipped undocumentedA technology radar board your architecture group works out ofTake-home review desk that runs candidate code in a sandboxDeploy control room for DigitalOcean App Platform appsFind the dbt models that are burning your warehouse budgetRun your whole Fly.io Machine fleet from one screenOne screen for every customer domain on your Fly.io apps