Skip to content

Conversation

perebaj
Copy link
Contributor

@perebaj perebaj commented Apr 5, 2025

Which issue(s) does the PR fix: Partially fixes #14409

This PR DRY the queue_manager.go code, creating a generic function to build timeseries (prompb.TimeSeries or writev2.TimeSeries)

I found this issue on the presentation shared by @bwplotka

Does this PR introduce a user-facing change?

NONE

Signed-off-by: perebaj <perebaj@gmail.com>
@perebaj perebaj force-pushed the build-generic-time-series branch from aeeecb2 to 8cd3b82 Compare April 5, 2025 18:02
Signed-off-by: perebaj <perebaj@gmail.com>
@perebaj perebaj marked this pull request as ready for review April 5, 2025 19:23
perebaj added 2 commits April 5, 2025 16:40
Signed-off-by: perebaj <perebaj@gmail.com>
Signed-off-by: perebaj <perebaj@gmail.com>

keepIdx := 0
lowest = math.MaxInt64
func buildWriteRequest(logger *slog.Logger, timeSeries []prompb.TimeSeries, metadata []prompb.MetricMetadata, pBuf *proto.Buffer, filter func(prompb.TimeSeries) bool, buf compression.EncodeBuffer, compr compression.Type) (_ []byte, highest, lowest int64, _ error) {
Copy link
Member

Choose a reason for hiding this comment

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

While we refactor, is there anything we can do to reduce number of arguments. Maybe have a requestBuilder object?

highest, lowest, timeSeries,
droppedSamples, droppedExemplars, droppedHistograms := buildTimeSeries(timeSeries, filter)

highest, lowest, wrappedTimeSeries, droppedSamples, droppedExemplars, droppedHistograms := buildGenericTimeSeries(wrappedTimeSeries, wrappedFilter)
Copy link
Member

Choose a reason for hiding this comment

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

Same with return arguments, this is generally not ideal (: It's ok to say "no, let's do this in the next iteration"

Copy link
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 take care of it in the next PR? I'm not sure if the approach that I'm taught is the best one. I would like to discuss/receive more comments about the generalization before diving into this "minors."

WDYT?

Some for this comment here

if droppedSamples > 0 || droppedExemplars > 0 || droppedHistograms > 0 {
logger.Debug("dropped data due to their age", "droppedSamples", droppedSamples, "droppedExemplars", droppedExemplars, "droppedHistograms", droppedHistograms)
}

// Convert back to prompb.TimeSeries
Copy link
Member

Choose a reason for hiding this comment

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

Comments ideally are full sentences, so they end with a period.

Suggested change
// Convert back to prompb.TimeSeries
// Convert back to prompb.TimeSeries.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Already take care of it here -> aa0c73a

@github-actions github-actions bot added the stale label Jun 17, 2025
Signed-off-by: perebaj <perebaj@gmail.com>
Signed-off-by: perebaj <perebaj@gmail.com>
@perebaj
Copy link
Contributor Author

perebaj commented Sep 11, 2025

Just sharing some thoughts

My plan to DRY the whole code here is to submit some small chunks of changes.

This PR creates a generic interface that deals with samples, exemplars, and histograms for both writev2.TimeSeries and ts prompb.TimeSeries. I'm using this implementation to create a generic time series builder: buildGenericTimeSeries. This function is used across buildWriteRequest and buildV2WriteRequest.

To DRY the whole queue_manager.go, we need to migrate the below "duplicated" functions. They are ordered according to the dependency graph and should respect this order to minimize disruption.

  • buildWriteRequest/buildV2WriteRequest
  • isTimeSeriesOldFilter/isV2TimeSeriesOldFilter
  • populateTimeSeries/populateV2TimeSeries
  • sendSamplesWithBackoff/sendV2SamplesWithBackoff
  • sendSamples/sendV2Samples

Maybe would be nice to add this checklist on the original issue. @bwplotka Is that make sense?

Signed-off-by: perebaj <perebaj@gmail.com>
Comment on lines +2145 to +2152
type TimeSeriesData interface {
// getSamples returns the samples in the time series
getSamples() []any
// getExemplars returns the exemplars in the time series
getExemplars() []any
// getHistograms returns the histograms in the time series
getHistograms() []any
}
Copy link
Contributor Author

@perebaj perebaj Sep 11, 2025

Choose a reason for hiding this comment

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

My main concern with this approach is whether returning a []any is the best solution. Since this forces every later interaction with a time series to explicitly check and convert the type, it increases the risk of runtime errors and reduces type safety. This pattern can also make the code harder to maintain because each consumer must validate and cast to the correct underlying type in order to access specific fields or methods.

I’d like feedback on better ways to achieve flexibility here 😀

I know that the only way to achieve this is using more generics. But I'm afraid to create a Frankenstein. Am I overengineering or/and overthinking, and the current approach is fair enough?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

remote write 2.0 - DRY the queue manager code
2 participants