You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We have more than 1 billion API calls per month to store analytics. When sending this through a CDN, as we do right now, this is really expensive (even above flat-rate premium plans from AWS)
Batch API calls, so that for example if you run a "brew install" with many dependencies, the number of events is reduced
In InfluxDB line protocol each line is one point, and the format defines \n as the separator between points.
/api/v2/write, the endpoint brew posts to, is built for batches: InfluxDB recommends sending up to about 5,000 lines per request. A batch of 10 is well within that.
InfluxDB 3 accepts the same /api/v2/write request, so this holds even if the server moves to v3.
Have you checked for other open Pull Requests for the same change?
Have you explained what your changes do? Performance claims (e.g. "this is faster") must include brew benchmark results.
Have you explained why you'd like these changes included, not just what they do?
For bug fixes, have you given step-by-step brew commands to reproduce the bug?
Have you written new tests (excluding integration tests)? Here's an example.
Have you successfully run brew lgtm (style, typechecking and tests) locally?
I did not use AI/LLM to create this PR, or I disclosed the tool/model below and reviewed its output; every commit has a human author or co-author and I will answer maintainer questions and review comments myself without AI/LLM.
Analytics events are now sent in batches, reducing the number of individual reporting requests.
Any remaining queued events are sent when the process exits, helping ensure they are included in reporting.
Influx analytics events are queued and sent in batches of ten. A process-local queue resets when inherited by another process, and the code registers a flush at process exit.
Changes: Influx analytics batching
Layer / File(s)
Summary
Queue, batch, and flush lifecycle Library/Homebrew/utils/analytics.rb, Library/Homebrew/test/utils/analytics_spec.rb
report_influx queues formatted events and flushes when the queue reaches ten lines. flush_influx_lines sends queued records as newline-separated data. The queue resets when the process ID changes, and the code registers a process-exit flush. The updated examples flush queued events after reporting.
Merge Risk: Low · up to 2bc13
Analytics batching mostly works, and the earlier test breakage is fixed. Two small edge cases remain: an event may be sent after a user opts out in the same run, and commands that replace the Ruby process may lose their analytics event. Both are bounded, so the change is mergeable with follow-up.
Pre-merge checks: 4
Check name
Status
Explanation
Title check
The title clearly and concisely describes the main change: batching analytics API calls.
Description check
The description explains the purpose of batching analytics API calls, the expected cost reduction, and the InfluxDB batching rationale.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Review info
Run configuration
Source mode: Auto
Repository: Unavailable
Branch: Unavailable
File: No configuration file from this repository applied
Commit: Unavailable
Layers: Organization UI
Review profile: CHILL
Plan: Advanced
Run ID: 7bfb937e-c135-4173-8ff0-ac34f91c9a60
Commits
Reviewing files that changed from the base of the PR and between 95d4938 and 8cd1d38.
Files selected for processing: 1
Library/Homebrew/utils/analytics.rb
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
We have more than 1 billion API calls per month to store analytics.
When sending this through a CDN, as we do right now, this is really expensive (even above flat-rate premium plans from AWS)
Batch API calls, so that for example if you run a "brew install" with many dependencies, the number of events is reduced
Even if we decide to go away from the CDN solution, reducing the number of calls is worthwile.
In InfluxDB line protocol each line is one point, and the format defines \n as the separator between points.
/api/v2/write, the endpoint brew posts to, is built for batches: InfluxDB recommends sending up to about 5,000 lines per request. A batch > of 10 is well within that.
InfluxDB 3 accepts the same /api/v2/write request, so this holds even if the server moves to v3.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
The reason will be displayed to describe this comment to others. Learn more.
Minor · Security & Privacy · Quick win
Discard queued events when analytics has been disabled.
With analytics initially enabled, brew analytics off queues its command event before running disable!. Command reporting precedes command execution in Library/Homebrew/brew.rb, Lines 132-134. The off subcommand calls disable! in Library/Homebrew/analytics/subcommand/off.rb, Lines 19-20. (raw.githubusercontent.com)
The exit callback then sends that event without checking the updated opt-out state. Before dispatch, recheck disabled? and not_this_run?. Clear the queue without sending when either check is true.
The reason will be displayed to describe this comment to others. Learn more.
Minor · Data Integrity & Integration · Quick win
Flush pending events before process replacement.
Command reporting runs before command execution in Library/Homebrew/brew.rb, Lines 132-134. However, brew ruby calls exec in Library/Homebrew/dev-cmd/ruby.rb, Lines 30-33. (raw.githubusercontent.com)
With the default batch size, its command event remains queued. Successful exec replaces the Ruby process, so this exit callback cannot send the event. Flush before supported process-replacement paths; retain the exit callback for normal termination. (docs.ruby-lang.org)
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is something we'll need to do. Honestly I'd consider something like a Thread as well/instead and just flush after no more events after a given period of time.
The reason will be displayed to describe this comment to others. Learn more.
@MikeMcQuaid An idle-time flush could send partial batches during long-running commands.
It would not replace a flush before exec: the process could be replaced before the timer fires. If we add a thread, the queue also needs synchronisation and fork-aware thread state. The exit flush can still handle normal termination.
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is something we'll need to do. Honestly I'd consider something like a Thread as well/instead and just flush after no more events after a given period of time.
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this approach could be simplified a bit and instead just get all the curl calls per e.g. brew install run and send them at once i.e. optimise the callers rather than change the underlying behaviour. That would allow both potentially larger batches and avoid the exit handling which is unlikely to be as reliable as the current approach.
We have more than 1 billion API calls per month to store analytics. When sending this through a CDN, as we do right now, this is really expensive (even above flat-rate premium plans from AWS)
Batch API calls, so that for example if you run a "brew install" with many dependencies, the number of events is reduced
Add a test that checks no request is sent for nine events and that the tenth sends one request containing all ten newline-separated records.
Review info
Run configuration
Source mode: Auto
Repository: Unavailable
Branch: Unavailable
File: No configuration file from this repository applied
Commit: Unavailable
Layers: Organization UI
Review profile: CHILL
Plan: Advanced
Run ID: d75cd06e-d687-4c32-a76a-260e768fc691
Commits
Reviewing files that changed from the base of the PR and between 0bcf90c and 2bc134f.
Files selected for processing: 2
Library/Homebrew/test/utils/analytics_spec.rb
Library/Homebrew/utils/analytics.rb
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
This branch has not been deployed
No deployments
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
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.
We have more than 1 billion API calls per month to store analytics. When sending this through a CDN, as we do right now, this is really expensive (even above flat-rate premium plans from AWS)
Batch API calls, so that for example if you run a "brew install" with many dependencies, the number of events is reduced
In InfluxDB line protocol each line is one point, and the format defines \n as the separator between points.
brew benchmarkresults.brewcommands to reproduce the bug?brew lgtm(style, typechecking and tests) locally?I have used Claude Opus 5.5 for this