feat: time-series download analytics - #2134
Open
netomi wants to merge 1 commit into
Open
Conversation
netomi
force-pushed
the
split/download-analytics
branch
from
September 2, 2026 16:09
3304111 to
4f71069
Compare
Makes the analytics live: the Timescale repository behind the seam the ingestion rework left inert, a query service, and a public endpoint for a download series. TimescaleDownloadAnalyticsRepository implements DownloadAnalyticsRepository against the time-series DSLContext, batching writes and reading the download_stats_daily aggregate. The interface regains findSeries, which was held back from the ingestion rework because it drags in the query model. DownloadAnalyticsService applies a settling margin (ovsx.analytics.settling-margin, 2 hours) so a series never ends on a bucket the continuous aggregate has not caught up to yet. DownloadAnalyticsAPI exposes the series, publicly cacheable. /api/version reports analyticsEnabled, so a client can tell whether the endpoints are there before calling them. Everything is gated on ovsx.analytics.enabled. With it off, no bean is created and captureDownload's ObjectProvider stays unsatisfied, exactly as before. Co-Authored-By: gnugomez <gomezbanaco@gmail.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
netomi
force-pushed
the
split/download-analytics
branch
from
September 3, 2026 14:46
4762381 to
7629c23
Compare
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.
Stack: 5 of 6. Split out of #2027. Base: #2133 (
split/timescale-datasource).Makes the analytics live: the Timescale repository behind the seam the ingestion rework left inert, a query service, and a public endpoint.
TimescaleDownloadAnalyticsRepositoryimplementsDownloadAnalyticsRepositoryagainst the time-seriesDSLContext, batching writes and reading thedownload_stats_dailyaggregatefindSeries, held back from refactor: rework the download ingestion pipeline #2132 because it drags in the query model (DownloadSeriesRequest,DownloadSeriesRowand their enums)DownloadAnalyticsServiceapplies a settling margin (ovsx.analytics.settling-margin, 2h) so a series never ends on a bucket the continuous aggregate has not caught up toDownloadAnalyticsAPIexposes the series, publicly cacheable/api/versionreportsanalyticsEnabled, so a client can tell whether the endpoints exist before calling themAll gated on
ovsx.analytics.enabled. With it off no bean is created andcaptureDownload'sObjectProviderstays unsatisfied, exactly as in the base.The thing to decide in this PR
This is where the request-path capture stops being inert, and it deserves a decision rather than a nod.
StorageUtilService.increaseDownloadCountis@Transactionaland called synchronously on the download path (LocalRegistryService:303, before the file response is returned).captureDownloadsits inside it.The transactional half is already handled, and deliberately:
b84a70cd3documents and enforces that writes run on the time-series pool and cannot join a caller's registry transaction — onesave()is one transaction of its own. So an analytics write is never rolled back with the registry's work, and never extends its atomicity.What remains is latency:
@Transactional, so it holds the registry's own JPA connection for that durationThis is the registry's hottest endpoint. The failure is handled (exceptions are swallowed so a download never fails for analytics), but slowness is not the same as failure. Whether that is acceptable, or whether the capture should be handed to an executor or dropped in favour of log-based ingestion alone, is a judgement for the maintainers — I have deliberately not changed the design.
It is also the one part of #2027 that is genuinely hard to see from the outside, which is most of why the stack put it here rather than in the ingestion PR.
Verification
Full server suite: 1216 tests passing (1179 from the base plus 37 here).
Refs #2027, #2025