gorilla-merger: Thanos-Receive-style fragment->TSDB merger (write path + StoreAPI) - #310
Merged
Merged
Conversation
…te path + StoreAPI)
New co-located Go module (own go.mod) implementing the "Merger (Track 2)" from
.design_docs/GORILLA_MERGER_DESIGN.md. Ingests Gorilla XOR-chunk fragments from
edge agents over HTTP, appends them to an embedded Prometheus tsdb.DB (2h block
range + WAL), ships completed 2h blocks to object storage via the Thanos shipper
(one PUT set per block, with the Thanos thanos{} meta), and exposes a Thanos
StoreAPI (gRPC) over the open <2h pending window so thanos-query can union
recent + S3 data.
Layout:
- cmd/gorilla-merger/main.go - env/flag wiring (HTTP, gRPC, tsdb dir, objstore
config, external labels); shipper auto-disabled when no objstore config.
- internal/merger/storage.go - tsdb.Open with 2h Min/MaxBlockDuration + WAL.
- internal/merger/ingest.go - POST /ingest/gorilla: gunzip ->
gorilla.DecodeFragmentBatch -> chunkenc.FromData(EncXOR) -> iterate ->
appender.Append(labels,t,v); external labels win on conflict; OOO/dup tolerated.
- internal/merger/storeapi.go - store.NewTSDBStore(component.Receive) over gRPC.
- internal/merger/shipper.go - shipper.New against a config-driven objstore
bucket; periodic Sync.
Imports the shared wire codec from github.com/ProjectASAP/asap-gorilla-go
(replace -> pinned checkout). Pins prometheus v0.308.0 / thanos v0.41.0; mirrors
Thanos's own replace directives (vimeo/galaxycache, grpc fork) which Go does not
inherit from a dependency's go.mod and which are required for the imported
pkg/store -> cacheutil -> cache closure to compile.
Tests (httptest + in-mem objstore): fragment encode -> POST -> tsdb readback
asserts samples; malformed body -> 400; full path ingest -> 2h block cut ->
shipper upload asserts a complete block (chunks+index+meta.json) with the
thanos{} section lands in the bucket.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…l replace) Replace the machine-local `replace => /mydata/asap-gorilla-pinned/...` with a versioned require on the now-standalone private module github.com/ProjectASAP/asap-gorilla-go v0.1.0, so the merger builds portably (CI/other machines) instead of only where the pinned checkout exists. Building requires GOPRIVATE=github.com/ProjectASAP/* + git auth. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…odule fetch The merger imports the private github.com/ProjectASAP/asap-gorilla-go module, so a naive `go build` in Docker/CI 404s/auth-prompts on the fetch. The multi-stage Dockerfile mounts a GitHub token as a BuildKit secret (never baked into a layer) and sets a transient in-container url.insteadOf git rewrite + GOPRIVATE so `go mod download`/`go build` resolve the private dep. Verified: image builds (86MB distroless) and the binary parses all flags. The same GOPRIVATE + gh_token-secret requirement applies to ASAPQuery-backend CI before PR #310 can merge (documented in the README). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
build(gorilla-merger): containerize via BuildKit secret (unblocks #310 CI)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New co-located Go module
gorilla-merger/(owngo.mod) implementing the Merger (Track 2) from.design_docs/GORILLA_MERGER_DESIGN.md(committed in this PR). It is a Thanos-Receive-style component, "Thanos Receive with an XOR-fragment frontend instead of remote-write."End-to-end data flow:
POST /ingest/gorilla): read body, gunzip whenContent-Encoding: gzip,gorilla.DecodeFragmentBatch(the shared wire codec fromgithub.com/ProjectASAP/asap-gorilla-go), then per fragmentchunkenc.FromData(chunkenc.EncXOR, f.Data), iterate the XOR chunk's samples, andappender.Append(labels, t, v). Labels =__name__=MetricName + fragment Attributes + the merger's external labels (external wins on conflict so distinct agents/mergers fan into distinguishable series). One appender per batch, committed once (WAL-durable on 200). OOO/duplicate samples are tolerated, not fatal. Malformed bodies -> 4xx; storage failures -> 5xx.tsdb.DBopened with the Prometheus default 2hMin/MaxBlockDurationand WAL on. The head holds the pending <2h window; it auto-compacts at the 2h boundary into on-disk blocks. Local retention kept short (default 6h) since blocks live in object storage once shipped.shipper.New(...)against a config-driven objstore bucket (the same bucketthanos-store-gatewaywatches),Syncon a ticker. One PUT set per 2h block (chunks + index + meta.json) with the Thanosthanos{}meta section written by the shipper.store.NewTSDBStore(logger, db, component.Receive, extLset)served over a gRPCstorepb.StoreServer. This is the open-window query surface; register it in thanos-query's store list so it fans in alongside store-gateway, and thanos-query unions recent (<2h pending) + S3 (>=2h) data. The backend's existingThanosQueryEngine(forward.rs) is unchanged.The Rust backend is untouched.
Module layout
cmd/gorilla-merger/main.go- env/flag wiring (HTTP addr, gRPC StoreAPI addr, tsdb dir, objstore config file, external labels, ship interval, retention). Shipper auto-disabled when no objstore config is supplied (write-path + StoreAPI still run).internal/merger/storage.go-tsdb.Openwith 2h block range + WAL.internal/merger/ingest.go- the/ingest/gorillahandler + decode/append.internal/merger/storeapi.go- ThanosTSDBStoreover gRPC.internal/merger/shipper.go- config-driven bucket + periodicshipper.Sync.Dependency notes
github.com/prometheus/prometheus v0.308.0andgithub.com/thanos-io/thanos v0.41.0(mutually compatible; Thanos v0.41.0 itself requires prometheus v0.308.0).asap-gorilla-go's API surface I use (Encode/DecodeFragmentBatch, theFragmenttype) carries no prometheus types, so the v0.307.3 -> v0.308.0 bump is transparent.asap-gorilla-gois pulled via areplace-> pinned checkout.replacedirectives (vimeo/galaxycache-> thanos-community fork, the grpc fork, kuberesolver). Go does NOT inherit a dependency'sreplacedirectives into the main module, and the importedpkg/store -> cacheutil -> cacheclosure does not compile against upstreamvimeo/galaxycache(itsCodecinterface differs). These mirrors are required for the build.Test plan
go build ./...go vet ./...clean,gofmt -l .cleango test ./... -count=1greengorilla.Fragments,gorilla.EncodeFragmentBatch, gzip, POST through the realhttptesthandler, query thetsdb.DB, assert samples + correct (external-merged) labels.db.Compact) -> shipperSyncagainst an in-memory objstore bucket -> assert a complete block (chunks + index + meta.json) lands with thethanos{}section and the external label.See
.design_docs/GORILLA_MERGER_DESIGN.mdfor the topology, wire contract, and cost levers.Generated with Claude Code.