Skip to content

Commit

Permalink
Merge pull request #315 from nats-io/ttl_refinements
Browse files Browse the repository at this point in the history
Refinements to MSG TTL spec during implementation
  • Loading branch information
ripienaar authored Jan 23, 2025
2 parents bc6f698 + 68de1a8 commit 57b94a7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea
.DS_Store
56 changes: 36 additions & 20 deletions adr/ADR-43.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
|----------|---------------------------------|
| Date | 2024-07-11 |
| Author | @ripienaar |
| Status | Approved |
| Status | Implemented |
| Tags | jetstream, client, server, 2.11 |

## Context and motivation

Streams support a one-size-fits-all approach to message TTL based on the MaxAge setting. This causes any message in the
Stream to expire at that age.
Streams support a one-size-fits-all approach to message TTL based on the MaxAge setting. This causes any message in the Stream to expire at that age.

There are numerous uses for a per-message version of this limit, some listed below:

Expand All @@ -22,26 +21,24 @@ Related issues [#3268](https://github.com/nats-io/nats-server/issues/3268)

## Per-Message TTL

We will allow a message to supply a TTL using a header called `Nats-TTL` followed by the duration as seconds.
### General Behavior

The duration will be used by the server to calculate the deadline for removing the message based on its Stream
timestamp and the stated duration.
We will allow a message to supply a TTL using a header called `Nats-TTL` followed by the duration as seconds or as a Go duration string like `1h`.

The TTL may not exceed the Stream MaxAge. The shortest allowed TTL would be 1 second. When no specific TTL is given
the MaxAge will apply.
The duration will be used by the server to calculate the deadline for removing the message based on its Stream timestamp and the stated duration.

Setting the header `Nats-No-Expire` to `1` will result in a message that will never be expired.
Setting the header `Nats-TTL` to `never` will result in a message that will never be expired.

A TTL of zero will be ignored, any other unparsable value will result in a error reported in the Pub Ack and the message
being discarded.

When a message with the `Nats-TTL` header is published to a stream with the feature disabled the message will be rejected with an error.

## Limit Tombstones

Several scenarios for server-created tombstones can be imagined, the most often requested one though is when MaxAge
removes last value (ie. the current value) for a Key.
Several scenarios for server-created tombstones can be imagined, the most often requested one though is when MaxAge removes last value (ie. the current value) for a Key.

In this case when the server removes a message and the message is the last in the subject it would place a message
with a TTL matching the Stream configuration value. The following headers would be placed:
In this case when the server removes a message and the message is the last in the subject it would place a message with a TTL matching the Stream configuration value. The following headers would be placed:

```
Nats-Applied-Limit: MaxAge
Expand All @@ -52,21 +49,40 @@ The `Nats-Limit-Applied` field is there to support future expansion of this feat

This behaviour is off by default unless opted in on the Stream Configuration.

### Sources and Mirrors

Sources and Mirrors will always accept and store messages with `Nats-TTL` header present, even if the `AllowMsgTTL` setting is disabled in the Stream settings.

If the `AllowMsgTTL` setting is enabled then processing continues as outlined in the General Behavior section with messages removed after the TTL. With the setting disabled the messages are just stored.

Sources may set the `SubjectDeleteMarkers` option and processing of messages with the `Nats-TTL` will place tombstones, but, Mirrors may not enable `SubjectDeleteMarkers` since it would insert new messages into the Stream it might make it impossible to match sequences from the Mirrored Stream.

## Stream Configuration

Weather or not a stream support this behavior should be a configuration opt-in. We want clients to definitely know
when this is supported which the opt-in approach with a boolean on the configuration would make clear.
Weather or not a stream support this behavior should be a configuration opt-in. We want clients to definitely know when this is supported which the opt-in approach with a boolean on the configuration would make clear.

We have to assume someone will want to create a replication topology where at some point in the topology these tombstone
type messages are retained for an audit trail. So a Stream with this feature enabled can replicate to one with it
disabled and all the messages that would have been TTLed will be retained.
We have to assume someone will want to create a replication topology where at some point in the topology these tombstone type messages are retained for an audit trail. So a Stream with this feature enabled can replicate to one with it disabled and all the messages that would have been TTLed will be retained.

```golang
type StreamConfig struct {
// AllowMsgTTL allows header initiated per-message TTLs
AllowMsgTTL bool `json:"allow_msg_ttl"`

// LimitsTTL activates writing of messages when limits are applied with a specific TTL
LimitsTTL time.Duration `json:"limits_ttl"`
// Enables placing markers in the stream for certain message delete operations
SubjectDeleteMarkers bool `json:"subject_delete_markers,omitempty"`
// When placing a marker, how long should it be valid, defaults to 15m
SubjectDeleteMarkerTTL string `json:"subject_delete_marker_ttl,omitempty"`
}
```

Restrictions:

* The `AllowMsgTTL` field must not be updatable.
* The `AllowMsgTTL` and `SubjectDeleteMarkerTTL` has a minimum value of 1 second.
* The `SubjectDeleteMarkers` setting may not be set on a Mirror Stream.
* The `SubjectDeleteMarkers` setting requires `AllowMsgTTL` and must error when not set.
* The `SubjectDeleteMarkerTTL` may only be set when `SubjectDeleteMarkers` is set.
* When `SubjectDeleteMarkerTTL` is unset the server will use `15m` as the default and will update the supplied configuration.
* When `SubjectDeleteMarkerTTL` is not given with `SubjectDeleteMarkers` set in Pedantic mode no default will be set and the request will fail.
* When `AllowMsgTTL` or `SubjectDeleteMarkers` are set the Stream should require API level `1`.

0 comments on commit 57b94a7

Please sign in to comment.