Skip to content

[feat][broker] PIP-470: Close inactive topics without deleting their data#25574

Open
codelipenghui wants to merge 2 commits intoapache:masterfrom
codelipenghui:penghui/jolly-nightingale-e2e980
Open

[feat][broker] PIP-470: Close inactive topics without deleting their data#25574
codelipenghui wants to merge 2 commits intoapache:masterfrom
codelipenghui:penghui/jolly-nightingale-e2e980

Conversation

@codelipenghui
Copy link
Copy Markdown
Contributor

PIP: #TBD (see pip/pip-470.md in this PR)

Motivation

Deployments with very large numbers of mostly-idle topics suffer broker memory pressure and per-topic metrics cardinality, even when they explicitly do not want the topic data deleted. Today the only mechanisms are:

  1. brokerDeleteInactiveTopicsEnabled — detects inactivity the right way, but deletes the data. Not acceptable when data must be retained.
  2. Manual pulsar-admin topics unload driven by an external cron — reimplements the broker's inactivity detection outside the broker.

This PR adds a first-class broker option that reuses the existing inactivity detection and closes (unloads) the inactive topic instead of deleting it. The topic's BookKeeper ledgers, subscriptions, cursors and policies are all preserved; only the in-memory PersistentTopic/NonPersistentTopic and its broker-cache entry are released. The next producer/consumer reconnect transparently reloads the topic.

Modifications

  • ServiceConfiguration: new dynamic config brokerCloseInactiveTopicsEnabled (default false).
  • PulsarService.start(): fail-fast validation — brokerDeleteInactiveTopicsEnabled and brokerCloseInactiveTopicsEnabled are mutually exclusive.
  • BrokerService.startInactivityMonitor(): schedule checkGC when either flag is on.
  • AbstractTopic.isCloseWhileInactive(): broker-level helper reading the new flag.
  • PersistentTopic.checkGC() / NonPersistentTopic.checkGC(): when close mode is active (and delete is not), after the same inactivity and replication-producer checks as today, call close(true, false). That path already disconnects clients, closes the managed ledger without deleting ledgers, and removes the topic from the broker cache via disposeTopicremoveTopicFromCache. The retention-window guard is bypassed in the close branch because it exists only to prevent data loss, which is moot when nothing is deleted.
  • Partitioned-topic metadata cleanup is not run in close mode (nothing is deleted).
  • Added pip/pip-470.md describing motivation, design, and interactions.

Detection inputs are unchanged and reused: brokerDeleteInactiveTopicsMode, brokerDeleteInactiveTopicsFrequencySeconds, brokerDeleteInactiveTopicsMaxInactiveDurationSeconds.

Verifying this change

This change added tests and can be verified as follows:

  • New InactiveTopicCloseTest:
    • testCloseInactiveTopicKeepsDataAndEvictsFromCache — produces a message, drops the subscription, waits for the inactivity window, asserts the topic is evicted from the broker cache (getTopicReference empty) but still listed in metadata, and a fresh consumer on a new subscription reads the original message from earliest — proving data is preserved.
    • testActiveTopicIsNotClosed — topic with an active subscription must not be closed.
    • testMutualExclusionWithDeleteInactive — broker startup fails when both flags are enabled.
  • Existing InactiveTopicDeleteTest (20 tests) — all pass; delete-path behavior is unchanged.

Does this pull request potentially affect one of the following parts:

  • The default values of configurations — a new configuration brokerCloseInactiveTopicsEnabled is introduced with default false; no existing configuration default is changed.

Documentation

  • doc-required — when this feature merges, the inactive-topic-management docs should be updated to describe the close-without-delete mode alongside the existing delete mode.

Matching PR in forked repository

PR in forked repository: https://github.com/codelipenghui/incubator-pulsar/tree/penghui/jolly-nightingale-e2e980

codelipenghui and others added 2 commits April 23, 2026 21:18
…data

Add `brokerCloseInactiveTopicsEnabled` (default false, dynamic) that unloads
topics determined inactive by the existing delete-GC detection, instead of
deleting them. The topic's BookKeeper ledgers, subscriptions, cursors and
policies are preserved; only the in-memory `PersistentTopic`/`NonPersistentTopic`
and the broker-side cache entry are released. The next producer/consumer
reconnect transparently reloads the topic.

Motivation: deployments with very large numbers of mostly-idle topics suffer
broker memory pressure and per-topic metrics cardinality even when they do
not want the data deleted. The manual `pulsar-admin topics unload` workaround
requires external polling. This PIP wires the same close path into the
inactivity monitor.

The new flag is mutually exclusive with `brokerDeleteInactiveTopicsEnabled`;
broker startup fails fast if both are on. Detection reuses
`brokerDeleteInactiveTopicsMode`, `brokerDeleteInactiveTopicsFrequencySeconds`
and `brokerDeleteInactiveTopicsMaxInactiveDurationSeconds`.

Tests:
- InactiveTopicCloseTest verifies that an inactive topic is evicted from the
  broker cache, data survives (a fresh subscription replays the message), an
  active topic is not closed, and the mutual-exclusion validation works.
- Existing InactiveTopicDeleteTest suite continues to pass unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the PIP label Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant