Skip to content

Add Extensions in *Result objects#743

Merged
alamb merged 6 commits into
apache:mainfrom
criccomini:extension-support-results
Jun 12, 2026
Merged

Add Extensions in *Result objects#743
alamb merged 6 commits into
apache:mainfrom
criccomini:extension-support-results

Conversation

@criccomini

@criccomini criccomini commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

We make extensive use of ObjectStore wrappers that do things like caching, metrics tracking, handle retries, and so on. We've found it would be helpful to use Extensions not just for requests (which are already supported today), but also responses.

One example: we have a CachedObjectStore in SlateDB that we are going to make pluggable. We have an internal metrics wrapper that (among other things) tracks cache hits/misses. Now that we're exposing the cache publicly, we need a way for our wrapper to track whether the reads were a hit or miss. An Extensions in the Result seems appropriate here. Then users that implement a cache can use the extension to signal such information.

This is just one example.

What changes are included in this PR?

Adds a public extensions: http::Extensions field to the existing result types (GetResult, PutResult, ListResult, and PaginatedListResult) mirroring the extensions field already present on the options structs (GetOptions, PutOptions, etc.). This gives ObjectStore implementations (e.g. caching wrappers) a way to return context-specific information, such as cache hit/miss status, to callers.

I did not add Extensions support for Delete/Head as there aren't Result types for these right now. That seemed like a heavier change.

Are there any user-facing changes?

  • GetResult, PutResult, ListResult, and PaginatedListResult gain a new public field extensions. Code constructing these types with struct literals must add the field (e.g. extensions: Default::default()).
  • PutResult no longer derives PartialEq/Eq; the manual impls compare e_tag and version only, ignoring extensions.

WARN: This was coded with Claude Fable with some steering from me. I (a human) wrote this PR summary.

Comment thread src/aws/client.rs Outdated
}

#[tokio::test]
async fn test_response_extensions_propagated() {

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.

This is the only test. Not sure if you want to clutter up the other ones with tests as well. Can do so if desired.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should add coverage of all new code, otherwise we coudl potentially break this feature in some future refactoring but not know

Not sure if you want to clutter up the other ones

I agree this test seems like a lot of boilerplate setup. It would be nice to avoid that

How about writing something similar to

/// Tests basic read/write and listing operations
pub async fn put_get_delete_list(storage: &DynObjectStore) {

And then calling it with an existing fixture, like

put_get_delete_list(&integration).await;

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.

Comment thread src/client/header.rs
#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))]
pub(crate) fn get_put_result(
headers: &HeaderMap,
response: crate::client::HttpResponse,

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.

Different ways to tackle this. LMK if you prefer another approach. Fable initially did a mut here which was kinda gross.

Comment thread src/http/client.rs

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @criccomini -- this looks good to me, other than I think we need test coverage for each object store. I left a suggestion, Let me know what you think

Comment thread src/lib.rs
/// response, allowing custom HTTP middleware to propagate information to callers.
///
/// These extensions are excluded from [`PartialEq`] and [`Eq`].
pub extensions: Extensions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this is technically a breaking API change (but that is ok as we are about to release a breaking release)

Comment thread src/aws/client.rs Outdated
}

#[tokio::test]
async fn test_response_extensions_propagated() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should add coverage of all new code, otherwise we coudl potentially break this feature in some future refactoring but not know

Not sure if you want to clutter up the other ones

I agree this test seems like a lot of boilerplate setup. It would be nice to avoid that

How about writing something similar to

/// Tests basic read/write and listing operations
pub async fn put_get_delete_list(storage: &DynObjectStore) {

And then calling it with an existing fixture, like

put_get_delete_list(&integration).await;

Comment thread src/list.rs Outdated
///
/// HTTP-backed stores in this crate populate this with the extensions of the HTTP
/// response, allowing custom HTTP middleware to propagate information to callers.
pub extensions: http::Extensions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Given that ListResult already has Extensions -- does it add additional value to add extensions to the PaginatedListResult as well?

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.

@criccomini

Copy link
Copy Markdown
Contributor Author

Great! I'll fix things up. 😀

@criccomini

Copy link
Copy Markdown
Contributor Author

Seems like the failed tests are flakes/unrelated to this PR?

@alamb

alamb commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Seems like the failed tests are flakes/unrelated to this PR?

Unrelated to the PR for sure. I'll check them out

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great to me -- thank you @criccomini

The MSRV check seems to be failing on installing cargo-msrv so that is unrelated to this PR

Comment thread src/aws/mod.rs
s3_encryption(&integration).await;
put_get_attributes(&integration).await;
list_paginated(&integration, &integration).await;
response_extensions(&integration, true).await;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍

@alamb
alamb merged commit 52f5119 into apache:main Jun 12, 2026
13 of 16 checks passed
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.

Support Extensions in *Result objects

2 participants