Hi Ulrik,

Thanks for raising this. I think this is a reasonable feature and worth a PIP.

I'd suggest implementing this as a policy setting at the topic,
namespace and broker level, consistent with how messageTTLInSeconds is
already configured. Rather than a pure on/off "is the subscription
active" check, it could be driven by the subscription cursor's
lastActive timestamp: when the setting is configured, TTL expiry is
skipped for a subscription only if less than the configured amount of
time has passed since its lastActive. This makes "active" precise and
tunable instead of binary, and it naturally covers the case where a
consumer disconnects (after the grace period the TTL resumes and old
messages get expired as before).

On the implementation side, the logic fits cleanly in
org.apache.pulsar.broker.service.persistent.PersistentMessageExpiryMonitor:
checkMessageExpiry()/the per-subscription expiry path would simply
skip expiry when the lastActive-based condition holds.

For naming, since messageTTLInSeconds is the existing setting, I'd
keep it in the same family and use a single time-based property:
messageTTLActiveSubscriptionGracePeriodSeconds

The semantics would be: if the value is <= 0 (the default), the
setting is ignored and the current behavior applies. When it is > 0,
TTL expiry is skipped for a subscription as long as less than this
many seconds have passed since the cursor's lastActive; once that
grace period elapses, TTL resumes as before. This keeps a single knob
that doubles as both the toggle and the threshold, expresses the
lastActive semantics directly, and reads alongside messageTTLInSeconds
thanks to the shared messageTTL prefix.

The grace period would be measured against the cursor's lastActive
timestamp. Note that when a topic is loaded, lastActive is set to the
current time regardless of whether a consumer has connected yet; this
is actually desirable here, as it prevents accidental TTL right after
a broker restart or load shedding before consumers have had a chance
to reconnect.

So yes, please go ahead and write up a PIP. Happy to review and give
feedback on the draft.

-Lari

On Thu, 4 Jun 2026 at 17:23, Ulrik Boll Djurtoft via dev
<[email protected]> wrote:
>
> Hi everyone!
>
> Been working with Pulsar for a few years now, but this is my first message on 
> this list.
>
> I’ve been playing around locally with a patch set for allowing one to 
> configure on a broker/namespace/topic level if the TTL should be applied to 
> subscriptions and replicators that are active.
>
> The motivation was that we have users that occasionally need to re-consume 
> historic events (within the retention policy) that are older than the TTL. 
> They do this by moving the cursor of their subscription backwards in time but 
> then get frustrated when the TTL gets applied and the cursor skips forward 
> “underneath” their consumer.
> Temporarily disabling the TTL on the topic works as a workaround, but it is 
> cumbersome, especially as the team needing it done often isn’t the team with 
> permissions to modify policies on the topic.
> By allowing the `checkMessageExpiry()` function to skip subscriptions that 
> are active we’d be able to leave the TTL policy in place which ensures that 
> old messages get expired properly for inactive subscriptions, while at the 
> same time not changing the state underneath active consumers.
> The default configuration would naturally be the current behaviour.
>
> So basically, my main question is this:
>
> Should I go ahead and make a PIP for this and clean it up for contributing, 
> or would it be a waste of time since it’d be undesirable as an option and 
> would be rejected anyway?
>
>
> Additionally, if I were to clean this up for contribution; would you like 
> separate toggles for ordinary subscriptions, replicators and shadow 
> replicators?
>
>
> Best regards
> Ulrik Boll Djurtoft
>
> Sr. IT Engineer
> Event Streaming Platform

Reply via email to