Implements the mongodb-superpowers-package design: Stable Tasks 1-50 and Advanced Tasks 1-15. The design assumes 19 Stable + 12 Advanced Gradle projects under modules/mongodb*. This repository's fail-closed registry declares exactly 19 leaf identities, so those modules become package boundaries inside the registered leaf :adapter:outbound:persistence-mongo, with the design's module dependency table enforced by ten ArchUnit rules. The mapping and every deviation are recorded in docs/mongodb/repository-adaptation.md. Contract highlights, all enforced by tests rather than convention: - Transaction body retry and commit retry are separate loops. A new session per body attempt; commit-only retry on an unknown commit. The body is never replayed after a commit ambiguity, so a failover cannot become a duplicate. - MongoExecutionOutcome keeps both ambiguous outcomes distinct from success and failure, and MongoFailureContext records only the design-permitted fields. - Failure classification reads server error labels before numeric codes. - BSON representations come from a pinned manifest, never a library default, and a golden type-signature gate fails on any drift. - Index and validator changes go through the manifest and the admin plane; metadata ownership gates every drop. - Every Advanced capability refuses construction unless its flag is enabled. Verified against real servers, not only unit tests. Running the lanes for the first time exposed four defects that a green `check` had hidden: - Four release lanes passed while executing zero tests; the gate now counts executed tests per lane and fails on zero. - The "single replica set" fixture was a standalone, because Testcontainers 2.x needs withReplicaSet(); its test only asserted a connection string. - The three-node fixture was three independent clusters, so no election could occur, and awaitNewPrimary() compared against the post-stop primary. - The migration lease checked modifiedCount, so a same-millisecond refresh read as a lost lease. scripts/verify-mongodb-platform.sh now reports: 9 lanes, 0 skipped, 0 failed, every evidence category produced. scripts/verify-mongodb-advanced.sh reports NOT PROMOTABLE: actual-topology evidence (real sharded cluster, real KMS, real target deployment) is unobtainable here, so it is named rather than assumed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
74 lines
3.2 KiB
Markdown
74 lines
3.2 KiB
Markdown
# Advanced — Time Series
|
|
|
|
**Capability:** `MongoCapability.TIME_SERIES`
|
|
**Property:** `ca-skeleton.persistence-mongo.advanced.time-series.enabled`
|
|
**Status:** Advanced.
|
|
|
|
## Requirements
|
|
|
|
| | |
|
|
|---|---|
|
|
| Topology | Replica set or sharded cluster. |
|
|
| Server | MongoDB 7.0 or 8.0. |
|
|
| Privilege | Standard application role; collection creation goes through the admin plane. |
|
|
|
|
## Descriptor
|
|
|
|
`MongoTimeSeriesDescriptor` declares:
|
|
|
|
- **timeField** — required, a BSON date. This is the bucketing axis.
|
|
- **metaField** — optional but nearly always wanted: the series identity (device id, tenant, sensor).
|
|
Documents sharing a `metaField` value bucket together, which is where the compression comes from.
|
|
- **granularity** — `MongoTimeSeriesGranularity`:
|
|
|
|
| Granularity | Bucket span | Use for |
|
|
|---|---|---|
|
|
| `SECONDS` | 1 hour | Sub-second to per-second ingest. |
|
|
| `MINUTES` | 24 hours | Per-minute metrics. |
|
|
| `HOURS` | 30 days | Hourly rollups. |
|
|
|
|
Granularity that is too fine produces many small buckets and loses the compression; too coarse
|
|
produces oversized buckets that must be read whole to answer a narrow query.
|
|
|
|
## What a time series collection is not
|
|
|
|
`MongoTimeSeriesCapabilityValidator` refuses the operations the collection type does not support, at
|
|
declaration time rather than at first use:
|
|
|
|
- **No arbitrary updates.** Time series data is append-mostly. Delete and limited update support
|
|
exists on recent servers but is not part of this platform's contract.
|
|
- **No unique index on the measurement.** There is no `_id` to be unique on in the usual sense.
|
|
- **No CSFLE.** Refused — see [encryption.md](encryption.md).
|
|
- **No change stream on the raw buckets** as a business event source. The bucket documents are a
|
|
storage representation, not your measurements.
|
|
|
|
Converting an existing regular collection to a time series collection is a copy, not an alter. Plan
|
|
it as a migration with a dual-write window.
|
|
|
|
## TTL
|
|
|
|
Time series collections use `expireAfterSeconds` on the collection rather than a TTL index on a
|
|
field. The [TTL rules](../schema-index-migration-guide.md#4-ttl) still apply: expiry is physical
|
|
cleanup on a bucket boundary, so a measurement can outlive its expiry by up to a bucket span plus the
|
|
monitor interval. Do not treat absence as a deadline.
|
|
|
|
## Operations
|
|
|
|
`MongoTimeSeriesOperations` is the port for insert and windowed read. Reads are bounded by the same
|
|
`MongoOperationBudget` as everything else: an unbounded time-range query on a time series collection
|
|
is the fastest way to read a year of data into heap.
|
|
|
|
## Failure recovery
|
|
|
|
| Symptom | Cause | Action |
|
|
|---|---|---|
|
|
| Writes rejected with an unsupported-operation error | An update or unique-index expectation | The collection type does not support it; change the access pattern. |
|
|
| Poor compression / large storage | Missing `metaField`, or granularity too fine | Both require a rebuild; measure on a copy before committing. |
|
|
| Slow range queries | Granularity too coarse for the query window | Same: rebuild with the granularity matched to the dominant query. |
|
|
|
|
## Promotion evidence
|
|
|
|
Actual-topology evidence on the target deployment, a migration path from the existing collection,
|
|
failure cases (unsupported update refused, CSFLE combination refused), and this document as the
|
|
runbook.
|