Skip to content

fix(services): persistence.mode is ignored by every managed service #75

Description

@vishr

Problem

persistence.mode is declared, validated, defaulted, and then ignored by every managed service.

Rendering a service that declares mode: ephemeral produces the same runtime as one that declares nothing:

services:
  redis:
    version: 8-alpine
    persistence:
      mode: ephemeral
command: exec redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes
volumes:
  - ob_sample_redis_data:/data

Measured against main. Two separate defects, and the volume is the larger one:

  1. The durable volume is created regardless of mode. ob_sample_redis_data is a named Docker volume with the usual ownership labels. persistence.mode currently governs volume ownership for workloads (internal/app/runtime.go:130); services never consult it.
  2. AOF is hardcoded on for redis and valkey (internal/app/services.go:131 and :139), so a service declared disposable fsyncs every write into that durable volume.

This is not limited to Redis. Every managed driver — redis, valkey, postgres, mysql, mongodb, clickhouse, rabbitmq, meilisearch, nats, minio — renders a durable data volume under mode: ephemeral.

The declaration has no effect on any managed service today.

Why it matters beyond tidiness

For a TTL-bounded cache — Monk's live quotes, forming bars, feed health, one-shot challenges — the current behaviour pays AOF fsync on every write for data the author has explicitly declared disposable, and accumulates it in a volume nothing intends to read back.

The reporting is wrong in the same direction: a service declared ephemeral still owns a durable volume, so it survives ob destroy without --volumes and counts as durable data with no backup.

Contract

Two owners, and the split is what makes an override safe.

Concern Owned by Overridable by settings?
Onebox volume: durable or disposable persistence.mode no
Server persistence flags (appendonly, save, driver equivalents) mode-derived default yes
Durable-data backup warning, destructive-transition gate persistence.mode no

persistence.mode is Onebox's own statement about data lifetime and is the thing it can enforce; a driver flag has no business changing it. settings covers the server's internals, where Onebox supplies a default derived from the mode and then gets out of the way.

Rules:

  • Omitted persistence stays equivalent to durable, so existing projects render byte-identically.
  • durable keeps today's behaviour exactly: durable volume, AOF on for Redis and Valkey, unchanged credentials, health, and connection semantics.
  • ephemeral produces no durable Onebox volume, and driver defaults that match: AOF and RDB off for Redis and Valkey, equivalents for other drivers where one exists.
  • Explicit settings win over the mode-derived default, and exactly one effective value is emitted per option. Today settingsRedisFlag appends after the hardcoded flags, so an authored appendonly: no renders --appendonly yes --appendonly no.
  • Where an explicit setting diverges from what the mode implies, ob canonical shows the effective value and where it came from, and ob doctor names the divergence in a sentence an operator can act on — for example, AOF enabled on ephemeral storage survives a restart but not a recreate. This is reported, not refused: the operator may choose it, but must not be misled by it.
  • Do not infer that TTLs make a service ephemeral. Data lifetime is declared, never guessed from application behaviour.

Stateful transition safety

durable to ephemeral abandons durable data and must remain a destructive persistence transition in ob plan. This issue changes what is rendered after that transition is accepted; it must not weaken the existing data-loss gate.

ephemeral to durable creates the managed volume and enables the durable defaults, without claiming any pre-transition data was migrated.

Scope

The mode-to-default derivation is small. The real work is in internal/app/services.go, where driver commands are literal strings with settings appended: producing one effective value per option means the command becomes computed rather than concatenated.

Whether every driver gains an ephemeral flag set, or only Redis and Valkey do in the first pass while the others merely stop creating a durable volume, is worth deciding explicitly rather than by omission.

Verification

  • Golden runtime: omitted and explicit durable render byte-identically to today, for every managed driver. The frozen contract digests already enforce this.
  • Golden runtime: ephemeral renders no durable Onebox volume, for every managed driver.
  • Golden runtime: ephemeral Redis and Valkey render with AOF and RDB off.
  • Explicit settings.appendonly and settings.save override the derived default and emit exactly one value per option.
  • ob canonical reports the effective persistence value and its origin; ob doctor names a divergence between explicit settings and the declared mode.
  • durable to ephemeral still requires the destructive data-lifetime acknowledgement in ob plan.
  • Ephemeral services raise no durable-data backup warning.
  • Generated authenticated URLs and health checks are unchanged in both modes.
  • Documentation states which layer each knob owns, and that the mode is not overridable by driver settings.

Done when

persistence.mode has an observable effect on every managed service: ephemeral is disposable in both Onebox storage ownership and server persistence behaviour, durable and omitted are unchanged from today, an explicit override is possible and visible, and every transition between the two stays explicit in the plan.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions