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
Non-reentrant grain timers #8955
base: main
Are you sure you want to change the base?
Non-reentrant grain timers #8955
Conversation
7a68791
to
a7f2806
Compare
a7f2806
to
7b4fa11
Compare
It's been a while since I've used Orleans but I think the current timer semantics are to only start counting for the next interval after the current callback completes. I'm not familiar with the internals here but that should definitely be maintained for non-reentrant timers. I saw |
A new method That could help make it more clear that this has the ability to be more Grain-integrated (ex. non-reentrant by default, lives for the life of the activation only) than a "normal" .NET timer. |
588cd19
to
2767c63
Compare
An alternative is to extract the parameters out into an "options" object like this: /// <summary>
/// Functionality for managing grain timers.
/// </summary>
public interface ITimerRegistry
{
// Existing API:
IGrainTimer RegisterTimer(IGrainContext grainContext, Func<object?, Task> callback, object? state, TimeSpan dueTime, TimeSpan period);
// New API - generic, accepts timer options struct
IGrainTimer RegisterGrainTimer<T>(IGrainContext grainContext, Func<T, Task> callback, T state, TimerCreationOptions options);
}
/// <summary>
/// Options for registering grain timers.
/// </summary>
public readonly struct TimerCreationOptions()
{
/// <summary>
/// The amount of time to delay before the timer callback is invoked.
/// Specify <see cref="Timeout.InfiniteTimeSpan"/> to prevent the timer from starting.
/// Specify <see cref="TimeSpan.Zero"/> to invoke the callback promptly.
/// </summary>
public required TimeSpan DueTime { get; init; }
/// <summary>
/// The time interval between invocations of callback.
/// Specify <see cref="Timeout.InfiniteTimeSpan"/> to disable periodic signaling.
/// </summary>
public TimeSpan Period { get; init; } = Timeout.InfiniteTimeSpan;
/// <summary>
/// Gets a value indicating whether callbacks scheduled by this timer are allowed to interleave execution with other timers and grain calls.
/// Defaults to <see langword="false"/>.
/// </summary>
/// <remarks>
/// If this value is <see langword="false"/>, the timer callback will be treated akin to a grain call. If the grain scheduling this timer is reentrant
/// (i.e., it has the <see cref="ReentrantAttribute"/> attributed applied to its implementation class), the timer callback will be allowed
/// to interleave with other grain calls and timers regardless of the value of this property.
/// If this value is <see langword="true"/>, the timer callback will be allowed to interleave with other timers and grain calls.
/// </remarks>
public bool Interleave { get; init; }
/// <summary>
/// Gets a value indicating whether callbacks scheduled by this timer should extend the lifetime of the grain activation.
/// Defaults to <see langword="false"/>.
/// </summary>
/// <remarks>
/// If this value is <see langword="false"/>, timer callbacks will not extend a grain activation's lifetime.
/// If a grain is only processing timer callbacks and no other messages, the grain will be collected after its idle collection period expires.
/// If this value is <see langword="true"/>, timer callback will extend a grain activation's lifetime.
/// If the timer period is shorter than the grain's idle collection period, the grain will not be collected due to idleness.
/// </remarks>
public bool KeepAlive { get; init; }
} |
47bfa8b
to
d43d20e
Compare
bcfaa40
to
0750f0c
Compare
Added a |
00d694f
to
938a883
Compare
I like that. We can still provide the "old" api for a while so people can migrate, or create their own extension to keep compatibility. I also like @rkargMsft suggestion to call the new api |
@benjaminpetit in regard to maintaining compat, do you also think we should retain the existing implementation?
Done, I've updated the API proposal snippet above. Do you feel we should also rename the options arg type, |
a4ee203
to
186d654
Compare
I like this approach! |
c1ee894
to
d5f5769
Compare
/// <param name="state">State object that will be passed as argument when calling the asyncCallback.</param> | ||
/// <param name="dueTime">Due time for first timer tick.</param> | ||
/// <param name="period">Period of subsequent timer ticks.</param> | ||
/// <returns>Handle for this Timer.</returns> | ||
/// <seealso cref="IDisposable"/> | ||
protected IDisposable RegisterTimer(Func<object, Task> asyncCallback, object state, TimeSpan dueTime, TimeSpan period) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed parameter & obsoleted API, otherwise kept everything the same.
/// <returns> | ||
/// An <see cref="IGrainTimer"/> instance which represents the timer. | ||
/// </returns> | ||
protected IGrainTimer RegisterGrainTimer<T>(Func<T, Task> callback, T state, GrainTimerCreationOptions options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New RegisterGrainTimer
API. Scheduling information is all in 'options' param.
dafb518
to
75ac054
Compare
var tmp = _waitingRequests.Select(m => m.Item1).ToList(); | ||
_waitingRequests.Clear(); | ||
return tmp; | ||
if (message.IsLocalOnly) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never forward local-only requests. We could rename this to IsActivationSpecific
or similar if "local-only" isn't clear enough
ee83996
to
385ad1a
Compare
385ad1a
to
07fff04
Compare
Fixes #2574
This builds on PRs which need to be merged first.
This PR currently adds a new
bool reentrant
parameter toRegisterTimer
:The parameter defaults to
true
to preserves the current behavior. We should not merge it as-is, instead we should decide how we want to expose non-reentrant timers. We could use a different API altogether. At the very least, we should use an overload to retain binary compatibility.Microsoft Reviewers: Open in CodeFlow