Skip to content

chore: remove span-metrics leftovers and lazy-init generator clients - #6618

Merged
javiermolinar merged 11 commits into
grafana:mainfrom
javiermolinar:chore/model-driven-generator-routing
Mar 13, 2026
Merged

chore: remove span-metrics leftovers and lazy-init generator clients#6618
javiermolinar merged 11 commits into
grafana:mainfrom
javiermolinar:chore/model-driven-generator-routing

Conversation

@javiermolinar

@javiermolinar javiermolinar commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

What this PR does:

Now that we have decoupled the livestores from the MetricsGenerator service we can now complete the cleanup. This pr does:

  • Metrics generator gprc path is removed
  • Simplifies the initialization, SingleBinary mode use a simple callback for pushing traces to the Metrics generator
  • Deprecate unnecesary configs
  • Remove all query-path from generator and proto code
  • Lazy-init generator clients in the distributor. Only for single binary mode.

How this has been tested:

  • Compiled locally and ran single-binary and distributed docker compose modes. As expected the single binary do no longer connect to Kafka for the distributor

Which issue(s) this PR fixes:
Fixes #

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]
Comment thread cmd/tempo/app/modules.go Outdated
t.cfg.Distributor.KafkaWritePathEnabled = t.cfg.Ingest.Enabled // TODO: Don't mix config params
t.cfg.Distributor.KafkaWritePathEnabled = false
t.cfg.Distributor.PushSpansToKafka = true
t.cfg.Distributor.PushSpansToGenerator = singleBinary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary until we implement the LiveStore grpc path

@javiermolinar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 552bd48166

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/tempo/app/modules.go
t.cfg.Distributor.KafkaConfig = t.cfg.Ingest.Kafka
t.cfg.Distributor.IngesterWritePathEnabled = false
t.cfg.Distributor.KafkaWritePathEnabled = t.cfg.Ingest.Enabled // TODO: Don't mix config params
t.cfg.Distributor.PushSpansToKafka = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate Kafka write-path enablement on actual ingest configuration

initDistributor now forces PushSpansToKafka = true for every target, which makes distributor.New() always validate Kafka settings and fail when ingest.kafka.topic is unset. With the current defaults (ingest.enabled: false, empty topic), this turns the default all target into a startup error path (ErrMissingKafkaTopic) even for configs that previously booted without Kafka; the test change to BackendScheduler masks this regression rather than fixing it. Please only enable Kafka routing when the deployment/config is actually Kafka-backed (or provide a non-empty default topic).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kafka is the only deployment model now unless we are in singlebinary mode. So this is totally right

Comment thread modules/distributor/distributor.go Outdated
@javiermolinar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f34eb0b7f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/tempo/app/modules.go

@mapno mapno left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the cleanup, but I think it can be further simplified.

Comment thread cmd/tempo/app/app_test.go
}()

config := NewDefaultConfig()
config.Target = BackendScheduler

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now setting up Kafka is mandatory. If we dont set it and we dont set target we get a validation error:

level=info msg="server listening on addresses" http=[::]:60047 grpc=[::]:60048
--- FAIL: TestApp_RunStop (30.00s)
    app_test.go:44: Checking Tempo is up...
    app_test.go:38:
                Error Trace:    /Users/javimolina/grafana/tempo.fork/cmd/tempo/app/app_test.go:38
                                                        /opt/homebrew/Cellar/go/1.26.0/libexec/src/runtime/asm_arm64.s:1447
                Error:          Received unexpected error:
                                failed to init module services: error initialising module: distributor: failed to create distributor: the Kafka topic has not been configured
                Test:           TestApp_RunStop
    app_test.go:43:
                Error Trace:    /Users/javimolina/grafana/tempo.fork/cmd/tempo/app/app_test.go:43
                Error:          Condition never satisfied
                Test:           TestApp_RunStop
FAIL
exit status 1
FAIL    github.com/grafana/tempo/cmd/tempo/app  30.994s

Until we make the whole target --all kafkaless we need to use a non kafka module. It can be the backendscheduler or any other one

KafkaConfig ingest.KafkaConfig `yaml:"kafka_config"`

// Internal routing toggle set by app wiring (not user-configurable).
PushSpansToKafka bool `yaml:"-"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this always true? Why have this param?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a placeholder. When we make the kafkaless mode this will be set to false instructing the distributor to not push to kafka

var generatorsPoolFactory ring_client.PoolAddrFunc = func(addr string) (ring_client.PoolClient, error) {
return generator_client.New(addr, generatorClientCfg)
if d.pushSpansToLocalFunc != nil {
d.generatorForwarder = newGeneratorForwarder(logger, d.sendToGenerators, o)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is a strong argument to keep all this complexity. If the push fails we can log the error and continue. No need to keep channels, workers, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main advantage of this is the decoupling between the distributor and the generator execution. Not that much for error handling but for e2e latency. We can remove it, or we can simplify it to a single bounded channel to not spawn infinite goroutines

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should follow up this in a different pr because it has some tradeoff we need to discuss

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the concern is decoupling, a goroutine or a simple buffered channel is sufficient. The current queuing code is over-engineered for an in-process call.

I'm ok to leave it if it gets addressed in another PR.

@javiermolinar
javiermolinar requested a review from mapno March 12, 2026 11:20

@mapno mapno left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, only a few comments

Comment thread cmd/tempo/app/modules.go
Comment on lines +250 to +258
var pushSpansToLocalGenerator distributor.PushSpansFunc
if singleBinary {
pushSpansToLocalGenerator = func(ctx context.Context, req *tempopb.PushSpansRequest) (*tempopb.PushResponse, error) {
if t.generator == nil {
return nil, errors.New("metrics-generator not initialized")
}
return t.generator.PushSpans(ctx, req)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about more kafkaless changes, it'd be nice to instead have a call in the distributor .AddDirectPush() that appends these types of calls, because we're going to need it for the live-store as well. That way it also doesn't change the happy path.

I'm fine if you prefer it this way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mind if we do it in a different pr? this is wired with the middleware and the shim and it involves some other changes

Comment thread cmd/tempo/app/modules.go Outdated
Comment thread cmd/tempo/app/modules.go
return t.generator, nil
}

func (t *App) initGeneratorNoLocalBlocks() (services.Service, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there is now no functional difference between the two can could be consolidated.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is something I want to tackle on a different PR. We need first to allow the initGenerator to use a different ring and differect codecs for at least one release since this target (initGeneratorNoLocalBlocks) is already in use

@javiermolinar
javiermolinar enabled auto-merge (squash) March 13, 2026 09:39
@javiermolinar
javiermolinar merged commit ec875f6 into grafana:main Mar 13, 2026
26 checks passed
@javiermolinar javiermolinar mentioned this pull request Apr 8, 2026
3 tasks
mattdurham pushed a commit to mattdurham/tempo that referenced this pull request Jun 18, 2026
…rafana#6618)

* chore: route generator by deployment model and deprecate ingest.enabled

* chore: remove metrics-generator query RPCs and handlers

* chore: remove span-metrics leftovers and lazy-init generator clients

* docs(changelog): add entry for grafana#6618

* breaking change

* manifest

* remove deprecated fields

* fix errored test

* remove generator grpc path

* fmt

* simplify code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants