Skip to content

feat(cogs): Create inventory-tracker crate for storage oplog - #588

Open
matt-codecov wants to merge 1 commit into
mainfrom
matth/storage-inventory-tracker
Open

feat(cogs): Create inventory-tracker crate for storage oplog#588
matt-codecov wants to merge 1 commit into
mainfrom
matth/storage-inventory-tracker

Conversation

@matt-codecov

Copy link
Copy Markdown
Contributor

Ref FS-210
Related to getsentry/sentry-kafka-schemas#497

Creates the inventory-tracker crate in our project that we will use to emit Kafka messages for a change stream that we will turn into a COGS pipeline.

This crate isn't Objectstore-specific at all. If/when another service wants to use it, we can move it to a separate repository and set up a release process for it. I just couldn't be bothered if nobody's asking for it.

PR(s) that use this new crate will be along soon.

@matt-codecov
matt-codecov requested a review from a team as a code owner August 5, 2026 06:09
@linear-code

linear-code Bot commented Aug 5, 2026

Copy link
Copy Markdown

FS-210

@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.73684% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.21%. Comparing base (3d77592) to head (6373531).

Files with missing lines Patch % Lines
objectstore-inventory-tracker/src/producer.rs 78.94% 12 Missing ⚠️
objectstore-inventory-tracker/src/kafka.rs 92.47% 7 Missing ⚠️
objectstore-inventory-tracker/src/tracker.rs 97.92% 6 Missing ⚠️
objectstore-inventory-tracker/src/test_utils.rs 84.21% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #588      +/-   ##
==========================================
+ Coverage   87.99%   88.21%   +0.21%     
==========================================
  Files          96      101       +5     
  Lines       15956    16488     +532     
==========================================
+ Hits        14041    14545     +504     
- Misses       1915     1943      +28     
Components Coverage Δ
Rust Backend 92.34% <ø> (ø)
Rust Client 81.97% <ø> (ø)
Python Client 93.31% <ø> (ø)

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jan-auer jan-auer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Initial review. Some of the below comments can be left for follow-up to get a first version in, as long as they don't change the overall concept and can be fixed in isolation. Particularly, shutdown is a larger topic.

Comment thread Cargo.toml Outdated
Comment thread Cargo.toml Outdated
Comment thread objectstore-inventory-tracker/src/lib.rs Outdated
/// Enqueues one record.
///
/// `key` controls which partition receives the message.
fn send(&self, key: &[u8], payload: Vec<u8>) -> Result<(), Self::Error>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

At least in arroyo / librdkafka, my understanding is that because of message batching sending a message can also fail after they were initially recorded. With the fire-and-forget style send API, these errors will not be returned anymore.

For us, this is likely fine - we want non-blocking best effort submission. Though we should pick one of the below options:

  • Acknowledge this in the doc comment and call out that not all errors can be captured
  • Make the signature infallible and move the responsibility for handling errors to the producer implementation.

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 on_delivery_failure argument to the Kafka producer should give callers a hook into failed messages. Failures here are when, like, the local queue is full or something.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the high-level interface, so callers should not have a concept about Kafka and should not need to hook the delivery callback. This is something the kafka producer impl can do internally.

To clarify my original message: we don't have to change anything, but we can write this into the doc comment so callers know that Ok() is not a guarantee.

Comment thread inventory-tracker/src/kafka.rs Outdated

@jan-auer jan-auer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good. See the open comments before merge, please.

Either in this PR or in a follow up, I'd suggest to add metrics, especially for errors.

@matt-codecov
matt-codecov force-pushed the matth/storage-inventory-tracker branch from 71877b3 to d180831 Compare August 7, 2026 01:45
@matt-codecov
matt-codecov force-pushed the matth/storage-inventory-tracker branch from d180831 to 6373531 Compare August 11, 2026 06:15
@jan-auer jan-auer changed the title feat(cogs): create inventory-tracker crate for storage oplog feat(cogs): Create inventory-tracker crate for storage oplog Aug 12, 2026

@jan-auer jan-auer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! Approving for merge, provided the comments below are solved

/// Enqueues one record.
///
/// `key` controls which partition receives the message.
fn send(&self, key: &[u8], payload: Vec<u8>) -> Result<(), Self::Error>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the high-level interface, so callers should not have a concept about Kafka and should not need to hook the delivery callback. This is something the kafka producer impl can do internally.

To clarify my original message: we don't have to change anything, but we can write this into the doc comment so callers know that Ok() is not a guarantee.


fn delivery(&self, result: &DeliveryResult<'_>, _opaque: Self::DeliveryOpaque) {
if let Err((error, _)) = result {
tracing::warn!(%error, "failed to deliver inventory record");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's dedicated syntax to pass errors so they get captured properly.

Suggested change
tracing::warn!(%error, "failed to deliver inventory record");
tracing::warn!(!!error, "failed to deliver inventory record");

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.

note to self, look into objectstore's tracing wrapper macro and basically inline what the !! does

///
/// Sending is asynchronous, so records handed over just before a process exits are
/// still sitting in a local queue. Call this during shutdown to deliver them.
fn flush(&self, timeout: Duration) -> Result<(), Self::Error>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note that backends use join terminology for this, but flush can also work here.

Let's make this async on the interface, so we can join it in the same way that we join backends. Internally, try to delegate to a spawn_blocking so that we do not block the executor when flushing the producer.

/// let producer = shared_producer(NoopProducer);
/// let tracker = InventoryTracker::new(producer.clone(), "my_gcs_bucket", 1.0);
/// ```
pub fn shared_producer<P>(producer: P) -> SharedProducer

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you can make this a provided method on the Producer trait so that you simply have to call .shared() for this.

Comment on lines +153 to +154
organization_id: Option<u64>,
project_id: Option<u64>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not blocking for this PR, but for later as we integrate and revise the API of this layer: Here we may want to take in scopes and usecase and then map this internally. This way, the backends and whoever is using inventory tracker don't need to perform this mapping.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants