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

ThreadLocalAccessor API capable of working in scoped scenarios #103

Merged
merged 7 commits into from
May 26, 2023

Conversation

chemicL
Copy link
Collaborator

@chemicL chemicL commented May 24, 2023

This change introduces two new methods: setValue(), and restore().

The first one can be called when entering a scope without a value defined,
while the second one allows clearing the ThreadLocal value upon closing a scope
when no surrounding ThreadLocal value was captured. This opens the possibility
to effectively clear ThreadLocal values if they are missing in the intended
scope (either coming from a ContextSnapshot or a Context object, acted upon by
the ContextAccessor).

This PR supersedes #100.

chemicL and others added 3 commits May 24, 2023 17:13
This change introduces two new methods: setValue(), and restore().

The first one can be called when entering a scope without a value defined,
while the second one allows clearing the ThreadLocal value upon closing a scope
when no surrounding ThreadLocal value was captured. This opens the possibility
to effectively clear ThreadLocal values if they are missing in the intended
scope (either coming from a ContextSnapshot or a Context object, acted upon by
the ContextAccessor).
@chemicL chemicL added this to the 1.0.3 milestone May 24, 2023
@chemicL chemicL self-assigned this May 24, 2023
Copy link
Collaborator

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

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

Overall looks good, but I'm thinking we should keep reset(). See comment under reset().

@chemicL
Copy link
Collaborator Author

chemicL commented May 26, 2023

@rstoyanchev regarding the recent comments, to gather the feedback in one place:

With the suggestion to keep reset(): I think if we keep reset(), there is no sense to have restore().

Let's assume ContextSnapshot implementations always call either setValue() or restore() (depending whether opening, or closing a scope), never reset(), as it can be ambiguous.

  • A: When both setValue() and restore() delegate to reset(), restore() and setValue() are not required to be overridden.
  • B: When setValue() behaves differently than restore() (and reset() will never be called), reset() will be exactly the same as setValue() or the same as restore().

There is never a need for 3 methods. However, reset() would be non-default, so users would be in a bit of trouble of deciding what to do in scenario B.

A is obvious: just implement reset(), it will be called in both cases.

With B: Ignore restore(), it defaults to reset() by default: we end up with setValue() and reset() implementations.

Thus, my suggestion is to get rid of restore(), just keep reset(). Let's allow the default setValue() to call it and instruct implementations to override if upon scope entry the behaviour is different than scope close, which will be calling reset().

The end API for writing to ThreadLocal would be the following:

ContextSnapshot.Scope open:

  • setValue(nonNullValue)
  • setValue() // null/missing, defaults to reset()

ContextSnapshot.Scope close:

  • restore(nonNullValue) // defaults to setValue(nonNullValue)
  • reset() // previous was null/missing

@rstoyanchev
Copy link
Collaborator

rstoyanchev commented May 26, 2023

@chemicL, I like the direction, more optimal for both basic and scope-aware style usage. Effectively, reset() remains the obvious method to implement in the basic case while setValue can be ignored, while for scope-awareness, one would use both setValue and reset().

The only thing I don't like is that reset() becomes ambiguous. On the hand, its name says "it's the method to clear". On the other hand, in the scope-aware scenario, reset has a more limited purpose, and "reset" becomes either setValue() or reset(), at which point the names really don't work any more.

Perhaps introducing a new reset(boolean) method, instead of setValue() would be a reasonable compromise to enable scope-aware usage without adding ambiguity. It would have a default implementation that delegates to reset(), which in turn could probably be deprecated, and eventually it becomes:

setValue(nonNullValue)
restore(nonNullValue)
reset(boolean)

@rstoyanchev
Copy link
Collaborator

After a further discussion offline, we'll stick with a design more explicit about scope awareness. After all that's how those methods are used, and the contract would make that more clear, as the PR is currently with reset() deprecated:

setValue(String)
setValue()
restore(String)
restore()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A general enhancement release notes Noteworthy change to call out in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants