Skip to content

Add tunnel cleanup sweep for abandoned resources#726

Open
aron-cf wants to merge 1 commit into
nextfrom
tunnels-cleanup-helper
Open

Add tunnel cleanup sweep for abandoned resources#726
aron-cf wants to merge 1 commit into
nextfrom
tunnels-cleanup-helper

Conversation

@aron-cf

@aron-cf aron-cf commented May 27, 2026

Copy link
Copy Markdown
Contributor

Long-lived deployments leak Cloudflare tunnels and their CNAME records when Durable Object cleanup never runs before the resources are abandoned — DO eviction, crashes, or a missed destroy() call all leave a tunnel and DNS record behind, counting against the per-account quota. Named-tunnel support (#722) created these resources but had no path to reclaim the ones that slip through.

This adds a @cloudflare/sandbox/tunnels entrypoint that sweeps stale SDK-owned tunnels and orphaned CNAME records, plus a scheduled handler factory for running it from a Worker Cron Trigger:

import { createScheduledTunnelCleanupHandler } from '@cloudflare/sandbox/tunnels';

export default {
  scheduled: createScheduledTunnelCleanupHandler({
    staleAfterMs: 24 * 60 * 60_000
  })
};
// wrangler.jsonc
"triggers": { "crons": ["0 3 * * *"] }

The handler reads credentials from env at invocation time and is a no-op when CLOUDFLARE_API_TOKEN is missing, so examples keep deploying without secrets. It uses CLOUDFLARE_TUNNEL_ACCOUNT_ID / CLOUDFLARE_ACCOUNT_ID when set and otherwise infers the account from a single-account token; CLOUDFLARE_ZONE_ID is inferred when unambiguous. Zone inference is treated as non-fatal: without a resolved zone the sweep still deletes stale tunnels and just skips DNS cleanup, reporting the reason through onError.

Deletion is deliberately conservative. The sweep only touches resources tagged createdBy: 'sandbox-sdk', refuses any tunnel missing its metadata.sandboxId tag (those surface in SweepResult.errors instead of being deleted), ignores unrecognized tunnel statuses, and removes a CNAME only when its target tunnel is absent from the account's live tunnel list and the record has aged past the stale window. A dryRun option reports the same SweepResult without issuing any deletes, so operators can inspect candidates before enabling destructive runs.

The lower-level sweepStale, listSandboxTunnels, and listSandboxDNSRecords helpers are exported for one-off audits and custom cleanup workflows.

Tests under packages/sandbox/tests/tunnels/ cover the inventory listing and pagination, the pure staleness/orphan planning rules, the metadata safety net, dry run, per-resource error isolation, and the scheduled handler's credential inference and cron-safe error handling.

@changeset-bot

changeset-bot Bot commented May 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 34b49e2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/sandbox Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented May 27, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@cloudflare/sandbox@726

commit: 34b49e2

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

🐳 Docker Images Published

Variant Image
Default cloudflare/sandbox:0.0.0-pr-726-34b49e25
Python cloudflare/sandbox:0.0.0-pr-726-34b49e25-python
OpenCode cloudflare/sandbox:0.0.0-pr-726-34b49e25-opencode
Musl cloudflare/sandbox:0.0.0-pr-726-34b49e25-musl

Usage:

FROM cloudflare/sandbox:0.0.0-pr-726-34b49e25

Version: 0.0.0-pr-726-34b49e25


📦 Standalone Binary

For arbitrary Dockerfiles:

COPY --from=cloudflare/sandbox:0.0.0-pr-726-34b49e25 /container-server/sandbox /sandbox
ENTRYPOINT ["/sandbox"]

Download via GitHub CLI:

gh run download 28513966368 -n sandbox-binary

Extract from Docker:

docker run --rm cloudflare/sandbox:0.0.0-pr-726-34b49e25 cat /container-server/sandbox > sandbox && chmod +x sandbox

Base automatically changed from tunnels-named to main May 28, 2026 09:44
@ghostwriternr ghostwriternr force-pushed the tunnels-cleanup-helper branch from 47baf86 to 8cf5e26 Compare July 1, 2026 10:51
@ghostwriternr ghostwriternr changed the title Add @cloudflare/sandbox/tunnels reconciler entrypoint Add tunnel cleanup sweep for abandoned resources Jul 1, 2026
Long-lived deployments can leak Cloudflare tunnels and CNAME records
when Durable Object cleanup does not run before resources are
abandoned (DO eviction, crashes, missed destroy calls). Add a
`@cloudflare/sandbox/tunnels` entrypoint that sweeps stale SDK-owned
tunnels and orphaned DNS records, plus a scheduled handler factory for
wiring it into a Cron Trigger.

Deletion is deliberately conservative: it only touches resources
tagged by this SDK, requires identifying metadata, ignores unknown
tunnel statuses, and removes a CNAME only when its target tunnel is
absent from the account's live tunnel list and the record has aged
past the stale window.

Co-authored-by: Aron <263346377+aron-cf@users.noreply.github.com>
@ghostwriternr ghostwriternr force-pushed the tunnels-cleanup-helper branch from 8cf5e26 to 34b49e2 Compare July 1, 2026 11:23
@ghostwriternr ghostwriternr changed the base branch from main to next July 1, 2026 11:23
@ghostwriternr ghostwriternr marked this pull request as ready for review July 1, 2026 11:24

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

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.

2 participants