Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document when with_key callbacks get invoked, and in which order #578

Closed

Conversation

joshtriplett
Copy link

@joshtriplett joshtriplett commented Aug 15, 2023

With some types of callbacks, it may matter what order the callbacks get
called in, and when in the formatting of the progress bar they're
called. For instance, if a with_key callback calls
ProgressBar::set_position, a subsequent reference to eta should
take that update into account.

Would appreciate having this documented as something callers can rely on.

With some types of callbacks, it may matter what order the callbacks get
called in, and when in the formatting of the progress bar they're
called. For instance, if a `with_key` callback calls
`ProgressBar::set_position`, a *subsequent* reference to `eta` should
take that update into account.
/// template, in order with other formatting and computation in the template. The caller can
/// rely on this ordering.
///
/// It's safe to call back into the `ProgressBar` from within this callback.
Copy link
Member

Choose a reason for hiding this comment

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

What's this for? I'm not all that comfortable with making this last sentence explicit. Changing the ProgressBar during ProgressTracker::write() is definitely not something I had in mind and really want to spend time considering as something that I should keep working.

Copy link
Member

Choose a reason for hiding this comment

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

I also think this might get into locking issues? Like, the ProgressTracker impl gets immutable access to the &ProgressState, which lives inside the BarState which is inside an Arc<Mutex<_>> inside the ProgressBar.

Copy link

Choose a reason for hiding this comment

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

The reason this works right now seems to be that (fortunately) the first thing the implementation does is to update its last-updated time with the current one before continuing with the update. Future calls to tick() will now immediately bounce off as the update seems to have just been done.
With that said, we also use the ticker-thread which may change the codepath, but the above is what I could gather by looking at the code.

Copy link
Member

Choose a reason for hiding this comment

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

ProgressBar::set_position() is rate-limited, yes, like ProgressBar::inc(), but ProgressBar::tick() isn't. So this is pretty nuanced, and not something that I want to guarantee to this level of detail going forward.

Copy link
Member

Choose a reason for hiding this comment

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

Anyway, it would be interesting to know why you want to do this. Presumably you can pass a ProgressBar clone into whatever thing that is making progress and call that outside of the ProgressTracker implementation.

Copy link

Choose a reason for hiding this comment

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

That's a great question: what problem is calling set_position() on a clone of the progress-bar from within the with_key() callback actually solving?

We have an ongoing operation which keeps updating an atomic counter which should be mapped to the pos of the progress bar. In order to do it with the current API it's necessary to use a callback which typically is more involved and noisy than passing a reference to an atomic down to where it needs to be. That noisiness was avoided by calling set_position() from within the with_key() callback.

An alternative solution could be to make the atomic counter that's used within the progress bar directly accessible - we use an auto-ticker so communicating via shared state would (seemingly) work.

I hope this context helps.

@joshtriplett
Copy link
Author

The use case for this is a piece of code that keeps stats in its own Arc of an Atomic, and wanting to use that as the position of the progress bar. We didn't want to have to maintain a thread polling the atomic, so instead, we let steady-tick do that for us. That alone would be easy enough with with_key, but we want the ETA calculation, which means updating the position. And it appears to work to call set_position from within the with_key callback.

What approach would you suggest for this use case? Assume the code that keeps stats doesn't have any indicatif-specific interface.

@djc
Copy link
Member

djc commented Aug 16, 2023

So here's what I think might make sense and wouldn't add too much complexity even though it's a bit involved:

pub trait ProgressInput {
    fn tick(&mut self, state: &mut ProgressState);
}

Then we'd add a method ProgressBar::enable_steady_tick_with_input() (mainly so this doesn't need a semver-breaking change) which, in addition to interval: Duration, also takes an input: Box<dyn ProgressInput>.

The input would stored in TickerControl and be invoked on &mut state.state before calling state.tick().

(Maybe not the best names, feel free to come up with better ones.)

How does that sound?

@chris-laplante any thoughts?

@Byron
Copy link

Byron commented Aug 16, 2023

This sounds like ProgressInput would be able keep a reference or ownership over any kind of counter which then somehow makes it into the pos field? If so, that should definitely work.

@djc
Copy link
Member

djc commented Aug 16, 2023

Would be great if someone working on the original issue (some Cargo/gitoxide thing?) could take a stab at implementing my proposal to see if it addresses the use case. Should be straightforward from my detailed comment before.

@Byron
Copy link

Byron commented Aug 17, 2023

Thanks for suggesting the fix and I hope it will be implemented eventually to not be lost in this PR. For us it seems less time consuming to use the current API as intended and make the set_position() calls where the counting happens, instead of in with_key().

With that said, I think this PR can be closed as it had to be rejected.
Thanks everyone.

@chris-laplante
Copy link
Collaborator

chris-laplante commented Dec 12, 2024

Closing in favor of something like #679

@Byron, @joshtriplett any comments would be welcome.

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.

4 participants