Skip to content

feat(core): add OwnedCounterGuard for cross-boundary tracking#265

Merged
jlizen merged 1 commit into
awslabs:mainfrom
jlizen:feat/owned-counter-guard
Apr 10, 2026
Merged

feat(core): add OwnedCounterGuard for cross-boundary tracking#265
jlizen merged 1 commit into
awslabs:mainfrom
jlizen:feat/owned-counter-guard

Conversation

@jlizen
Copy link
Copy Markdown
Contributor

@jlizen jlizen commented Apr 10, 2026

📬 Issue #, if available:

Closes #264

✍️ Description of changes:

Summary

CounterGuard borrows &'a AtomicU64, which prevents it from being stored in structs that outlive the borrow (e.g. response body wrappers in tower middleware). Users currently fall back to manual fetch_add/fetch_sub, losing RAII safety.

This adds OwnedCounterGuard, which holds an Arc<Counter> instead of a reference. It has the same Drop behavior (saturating decrement) and the same CloseValue impls as CounterGuard, but can be freely moved across async boundaries.
a📬 Issue #, if available:

Closes #264

✍️ Description of changes:

Summary

CounterGuard borrows &'a AtomicU64, which prevents it from being stored in structs that outlive the borrow (e.g. response body wrappers in tower middleware). Users currently fall back to manual fetch_add/fetch_sub, losing RAII safety.

This adds OwnedCounterGuard, which internally shares the counter and can be freely moved across async boundaries. It has the same Drop behavior (saturating decrement) and the same CloseValue impls as CounterGuard.

The guard is Clone. Cloning shares the underlying counter without incrementing it; each clone independently decrements on drop. Callers are responsible for ensuring the counter has been incremented a corresponding number of times.

The constructor is Counter::increment_scoped_owned(self: &Arc<Self>), mirroring the existing Counter::increment_scoped(&self) API.

OwnedCounterGuard is re-exported from both metrique-core and the top-level metrique crate.

Testing

Unit tests covering increment/drop semantics, saturation at zero, CloseValue behavior, cross-thread movement, and multiple concurrent guards on the same counter.

🔏 By submitting this pull request

  • I confirm that I've made a best effort attempt to update all relevant documentation.
  • I confirm that my contribution is made under the terms of the Apache 2.0 license.
    The constructor is Counter::increment_scoped_owned(self: &Arc<Self>), mirroring the existing Counter::increment_scoped(&self) API. The caller wraps their Counter in an Arc, which is the natural choice for shared state in async contexts.

OwnedCounterGuard is re-exported from both metrique-core and the top-level metrique crate.

Testing

Unit tests covering increment/drop semantics, saturation at zero, CloseValue behavior, cross-thread movement, and multiple concurrent guards on the same counter.

🔏 By submitting this pull request

  • I confirm that I've made a best effort attempt to update all relevant documentation.
  • I confirm that my contribution is made under the terms of the Apache 2.0 license.

@jlizen jlizen requested a review from rcoh April 10, 2026 22:38
Comment thread metrique-core/src/atomics.rs Outdated
Comment thread metrique-core/src/atomics.rs Outdated
Comment thread metrique-core/src/atomics.rs Outdated
self.0
.0
.fetch_update(
std::sync::atomic::Ordering::Relaxed,
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 seems wrong

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.

i can name it

Comment thread metrique-core/src/atomics.rs Outdated
@jlizen jlizen force-pushed the feat/owned-counter-guard branch from aba6408 to 09ef761 Compare April 10, 2026 23:27
@jlizen jlizen force-pushed the feat/owned-counter-guard branch from 09ef761 to c6faa24 Compare April 10, 2026 23:31
@jlizen jlizen requested a review from rcoh April 10, 2026 23:41
@jlizen jlizen merged commit b3dfce2 into awslabs:main Apr 10, 2026
10 checks passed
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.

metrique: Counter::increment_scoped should support an owned guard variant

2 participants