Repository navigation
add bus prune to remove the subscriptions and bindings a bus no longer needs - #364
Open
adenhertog wants to merge 3 commits into
Open
adenhertog wants to merge 3 commits into
adenhertog wants to merge 3 commits into
Conversation
…r needs Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ort partial failures - bus.prune() takes an approved list (only), which bus prune --apply sets to what it printed - transports try every removal and return removed, failed and notFound; bus.prune() throws PruneIncomplete on failures - sqs skips subscriptions with raw delivery, a filter or redrive policy or a role - allowCustomHandlersWithoutTopic / --allow-custom-handlers opts in to pruning custom handlers without a topic - move the cli prune fixture into test/provision so it needs no lockfile importer Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #283
Summary
Adds
bus pruneandbus.prune({ apply }), which find the subscriptions and bindings of a service's own queue to topics or exchanges it no longer handles and, with--apply, remove them. SQS and RabbitMQ implement it.Background
#333 delivered
bus provision. #283 was narrowed to pruning: after a rollout, removing what the configuration no longer needs, with a report-only default and SQS and RabbitMQ support.Problem
Provisioning only adds. When a service stops handling a message, its queue stays subscribed (SNS) or bound (RabbitMQ), so it keeps receiving the message and the bus discards it. Nothing cleans that up.
Approach
bus.prune({ apply?, only?, allowEmpty?, allowCustomHandlersWithoutTopic? })calls the new optionalTransport.prune(TransportPruneOptions)(provision's options withapplyinstead ofdryRun, plusonly) and returnsPruningPlan[]({ adapter, resources, removed, failed, notFound }, reusingProvisionedResource).onlyis an approved list: transports remove only what's both in it and still found, and report the rest innotFound. Withapply, transports try every removal and return failures infailed;bus.prune()then throwsPruneIncomplete, whoseplanssay exactly what was removed and what failed. It throwsPruneRefusedfor a send-only bus or a scheduler, a bus that handles nothing unlessallowEmpty, and a bus with a custom handler without atopicIdentifierunlessallowCustomHandlersWithoutTopic(for handlers whose messages are sent straight to the queue, such as S3 notifications).ListSubscriptions(the caller's own subscriptions in the client's region), keepssqssubscriptions whose endpoint is the service queue, and reports those to topics outsideplanResources().subscriptions. It reads each candidate withGetSubscriptionAttributesand skips, with a warning, any with raw message delivery, a filter policy, a redrive policy or a subscription role, which the bus never sets. Withapplyit unsubscribes them, settling every call.onlymatches onsubscriptionArn. Pending subscriptions are skipped. The queue policy, topics and queues are never touched.managementUrl(credentials and vhost default fromconnectionString;RabbitMqManagementUrlMissingwith fix-it help when it's missing). It listsGET /api/queues/{vhost}/{queue}/bindingsand only keeps bindings shaped like the bus' own: from a fanout exchange, routing key'', no arguments, never the default exchange or the queue's own exchange. It unbinds over AMQP, one channel per binding, so a refused unbind (which closes the channel) doesn't fail the rest.onlymatches on exchange and queue.bus prune <module> [--export] [--apply] [--allow-empty] [--allow-custom-handlers] [--check] [--json], using the same loader asbus provision. It always does a report-only pass first and prints it before removing anything (to stderr with--json), then passes exactly what it printed asonly, so it never removes anything it didn't print. The JSON isPruneReport(formatVersion: 1, withremoved,failedandnotFoundper adapter). On a partial failure it prints the report, then the error, and exits 1. Exit codes are 0, 1 (load, refusal or failure), 2 (usage, including--check --apply) and 3 (--checkfound something).bus provisionof the old version), the approved-list and partial-failure behaviour, the custom-handler opt-in, and removing an old queue with the broker's tools. Each adapter page has a "Pruning" section with its deploy permissions (SQS now includessns:GetSubscriptionAttributes, and notes that cross-account and cross-region subscriptions are never found). The custom transport page, the bus-cli and bus-rabbitmq READMEs and the CLAUDE.md files are updated too.only,PruneIncompleteand refusals (including the opt-in); the CLI with the fake importer (including the race where more is found between printing and removing, and a partial failure in text and JSON) and throughbus.mjs; both transports with mocked clients (approved lists, hand-made SNS subscriptions, a failed unsubscribe or refused unbind not stopping the rest). Integration tests on LocalStack and RabbitMQ provision with handlers A and B, then prune with only A. They check the dry run lists B,applywith an approved list removes only that,applyremoves B, another queue's subscription or binding to B survives, external custom-handler topics are kept or removed correctly, raw and filtered SNS subscriptions and bindings not made by the bus survive, and the refusals hold.The CLI's prune fixture lives in
test/provision/(sharing itstype: modulepackage.json), so it needs no lockfile importer.Follow-ups for other transports: #361 (Postgres transport), #362 (bus-redis) and #363 (Azure Service Bus, blocked by #346).
pnpm changeset) for user-facing changes to published packages, or none is neededdocs/for user-facing changes, or none needed🤖 Generated with Claude Code