Sends billing.events log lines to S3 - #2522
Open
Hazel-Datastax wants to merge 66 commits into
Open
Conversation
Contributor
📉 Unit Test Coverage Delta vs Main Branch
|
Contributor
Unit Test Coverage Report
|
erichare
self-requested a review
September 1, 2026 17:46
erichare
reviewed
Sep 1, 2026
erichare
reviewed
Sep 1, 2026
erichare
reviewed
Sep 1, 2026
erichare
reviewed
Sep 1, 2026
erichare
reviewed
Sep 1, 2026
4 tasks
still needs decisions on what to do when upload fails. Installer setup to do basic starting of the uploader.
erichare
reviewed
Sep 4, 2026
| Map<String, String> props = new HashMap<>(); | ||
| props.put("stargate.jsonapi.billing.s3.enabled", "true"); | ||
| props.put("stargate.jsonapi.billing.s3.bucket", BUCKET); | ||
| props.put("stargate.jsonapi.billing.s3.bucket-region", BUCKET_REGION); |
Contributor
There was a problem hiding this comment.
Suggested change
| props.put("stargate.jsonapi.billing.s3.bucket-region", BUCKET_REGION); | |
| props.put("stargate.jsonapi.billing.s3.region", BUCKET_REGION); |
erichare
reviewed
Sep 4, 2026
| props.put("stargate.jsonapi.billing.s3.bucket-region", BUCKET_REGION); | ||
| props.put("stargate.jsonapi.billing.s3.endpoint-override", httpEndpoint); | ||
| // Small thresholds so the export flushes promptly: count seal at 5, age sweep every 2s. | ||
| props.put("stargate.jsonapi.billing.s3.max-events", "5"); |
Contributor
There was a problem hiding this comment.
Suggested change
| props.put("stargate.jsonapi.billing.s3.max-events", "5"); | |
| props.put("stargate.jsonapi.billing.s3.max-batch-size", "5"); |
erichare
reviewed
Sep 4, 2026
| props.put("stargate.jsonapi.billing.s3.endpoint-override", httpEndpoint); | ||
| // Small thresholds so the export flushes promptly: count seal at 5, age sweep every 2s. | ||
| props.put("stargate.jsonapi.billing.s3.max-events", "5"); | ||
| props.put("stargate.jsonapi.billing.s3.max-age", "PT2S"); |
Contributor
There was a problem hiding this comment.
Suggested change
| props.put("stargate.jsonapi.billing.s3.max-age", "PT2S"); | |
| props.put("stargate.jsonapi.billing.s3.max-batch-age", "PT2S"); |
erichare
reviewed
Sep 4, 2026
| // Small thresholds so the export flushes promptly: count seal at 5, age sweep every 2s. | ||
| props.put("stargate.jsonapi.billing.s3.max-events", "5"); | ||
| props.put("stargate.jsonapi.billing.s3.max-age", "PT2S"); | ||
| props.put("stargate.jsonapi.billing.s3.shutdown-timeout", "PT5S"); |
Contributor
There was a problem hiding this comment.
Suggested change
| props.put("stargate.jsonapi.billing.s3.shutdown-timeout", "PT5S"); | |
| props.put("stargate.jsonapi.billing.s3.upload-shutdown-deadline", "PT5S"); |
erichare
reviewed
Sep 4, 2026
| .atMost(Duration.ofSeconds(10)) | ||
| .untilAsserted( | ||
| () -> | ||
| assertThat(metricTotal("billing_s3_events_flushed_total")) |
Contributor
There was a problem hiding this comment.
I think BatchedLogUploaderMetrics now registers billing.s3.uploaded.events, which Prometheus exposes as billing_s3_uploaded_events_total... so that should be what we check here. Correct me if im wrong
erichare
reviewed
Sep 4, 2026
| .atMost(Duration.ofSeconds(60)) | ||
| .pollInterval(Duration.ofSeconds(2)) | ||
| .untilAsserted( | ||
| () -> assertThat(metricTotal("billing_s3_batches_failed_total")).isGreaterThan(0.0)); |
Contributor
There was a problem hiding this comment.
Same as above, i think this should be billing_s3_failed_batches_total
erichare
reviewed
Sep 4, 2026
| props.put("stargate.jsonapi.billing.s3.bucket", BUCKET); | ||
| props.put("stargate.jsonapi.billing.s3.bucket-region", BUCKET_REGION); | ||
| props.put("stargate.jsonapi.billing.s3.endpoint-override", httpEndpoint); | ||
| // Small thresholds so the export flushes promptly: count seal at 5, age sweep every 2s. |
Contributor
There was a problem hiding this comment.
Should we set stargate.jsonapi.billing.s3.upload-sleep-duration to something short around here?
erichare
reviewed
Sep 4, 2026
| * billing.events} JUL logger, the disabled path, and fail-loud startup on bad config. Delivery | ||
| * through an installed handler is covered by {@code BillingS3ExportIntegrationTest}. | ||
| */ | ||
| class BillingS3HandlerInstallerTest { |
erichare
reviewed
Sep 4, 2026
| * flush()/notify() on an object lands before the upload thread is in wait() - if we used | ||
| * Object.notify() and .wait() | ||
| */ | ||
| private final Semaphore wakeupPermit = new Semaphore(0); |
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.
What this PR does:
Sends
billing.eventslog lines to S3 as batched NDJSON objectsHow it works:
BillingS3HandlerInstallerwires it up: attachesBillingS3LogHandlerto thebilling.eventsJUL logger at startup, detaches/closes it at shutdown.BillingS3LogHandleris the orchestrator.publish()pushes each line intoBillingQueue; the handler then decides when to ship — batch sealed (count/bytes), age tick, orclose()drain — gates upload concurrency, calls the uploader, and records outcomes viaBillingMetrics. Delivery is at-most-once by design: publish never blocks on S3, a full queue drops events, shutdown drains best-effort within a timeout.BillingQueueowns the batching policy (seal by max events/bytes) and hands out drained batches.S3BatchUploaderis the only S3-aware piece (AsyncBatchUploaderimpl) — encodes NDJSON, PUTs to a time-partitioned key.BillingMetricstracks offered/flushed/failed/dropped counts plus a delivery heartbeat.Tests
BillingS3LogHandlerTestis the main coverage: per-method unit tests (flush triggers, failure containment, close draining), plus concurrency tests (multi-producer no-loss/no-dup, close racing with in-flight publish) and pipeline tests (concurrency gate, auto-chaining the next batch on settle).BillingS3ExportIntegrationTestcovers the real path end-to-end against S3Mock, including that a dead S3 endpoint never breaks the API.Which issue(s) this PR fixes:
Fixes #
Checklist