Skip to content

feat: configurable per-application message retention period - #1063

Closed
carlosalbertorg wants to merge 1 commit into
gotify:masterfrom
carlosalbertorg:feat/message-retention
Closed

carlosalbertorg wants to merge 1 commit into
gotify:masterfrom
carlosalbertorg:feat/message-retention

Conversation

@carlosalbertorg

Copy link
Copy Markdown

Closes #376.

What this does

  • Application gets a RetentionSeconds field (0 = use the server's default, mirrors the existing Client.ExpiresAfterInactivitySeconds pattern).
  • A new GOTIFY_MESSAGERETENTIONSECONDS env var sets the server-wide default for applications that don't set their own retention period (also 0 = unlimited, i.e. today's behavior is preserved with no config change).
  • A new goroutine ticker (next to the existing client-cleanup one in router.go) calls PruneMessages every minute, deleting messages older than the applicable retention period.
  • The admin UI's Create/Edit Application dialogs get a "Message Retention (seconds, 0 = server default)" field, and the Applications table shows it.

This is exactly the spec from the issue:

Each application should get a separate setting for the retention period. The pruning should be done in a separate goroutine that executes an sql query every minute to prune messages outside of the retention period. The default retention period should be unlimited.

Scope note

Later comments on the issue discussed a richer hierarchy (a hard global max, a separate global default, per-message overrides, etc.). I deliberately did not build that - it was never fully settled even among commenters, and this codebase has no existing pattern for a runtime-editable global setting (everything global is env-var/startup config, e.g. config/config.go). Happy to extend this if a global default isn't enough and a hard max is also wanted - figured it's better to ship the agreed-upon core first.

Testing

  • New DatabaseSuite.TestPruneMessages (per-app override, global default, and "both zero = unlimited" cases, plus a boundary check at the exact cutoff).
  • New Test_UpdateApplicationRetentionSeconds_expectSuccess in the API suite.
  • Updated Test_ensureApplicationHasCorrectJsonRepresentation for the new JSON field.
  • Updated the Puppeteer application.test.ts column indices (the new UI column shifted them).
  • go test ./..., golangci-lint run, and the full ui yarn lint/format/build/test all pass locally (only the Docker-dependent OIDC/dex tests don't run in my environment - unrelated, pre-existing).
  • docs/spec.json regenerated via swagger generate spec.

Applications now have a RetentionSeconds field (0 = use the server's
default). A new GOTIFY_MESSAGERETENTIONSECONDS env var sets that
server-wide default for applications that don't override it. A
background goroutine prunes expired messages every minute.

This follows the spec from gotify#376: "Each application should get a
separate setting for the retention period. The pruning should be
done in a separate goroutine that executes an sql query every minute
to prune messages outside of the retention period. The default
retention period should be unlimited."

Closes gotify#376
@carlosalbertorg
carlosalbertorg requested a review from a team as a code owner September 30, 2026 14:51
@jmattheis

Copy link
Copy Markdown
Member

Thanks for the contribution. As said in my last comment, I've already started working on this, with the implementation as described in here #376 (comment)

@jmattheis jmattheis closed this Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Configurable retention period for messages.

2 participants