You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Queue immediately due grain timer ticks directly as local-only activation requests instead of routing them through the physical timer. Preserve normal interleaving and keep-alive rules and start a fresh call chain. Delayed timing and resolution remain owned by the configured TimeProvider. Timer messages use the factory's explicit context-free path so ambient request data is neither copied nor mutated; ordinary requests retain their existing context export behavior.
Keep the physical timer eagerly created and readonly. Use one Idle/Busy/Disposed lifecycle, where Busy covers both the queued turn and its running callback. Reserving a turn defaults its following delay to the period; Change replaces that following schedule. A queued callback keeps its turn, and changes while queued or running take effect after it completes, with the latest due time and period winning. This avoids separate queued/running bookkeeping and replacement-arm invalidation.
A small state lock coordinates provider callbacks with grain-side scheduling and runtime disposal. Enqueue local activation messages and run cancellation registrations outside that lock to preserve shutdown ordering. Disposal is terminal before cancellation registrations execute, so queued messages drain and admitted callbacks receive cancellation. Activation enqueueing is a local operation: the timer relies on that guarantee rather than modeling recoverable delivery failure or resetting and re-arming its schedule. The existing boundary logger reports unexpected runtime exceptions; application callback and cancellation-registration exceptions retain their established handling.
The focused tests cover distinct contracts: immediate activation admission, normal versus context-free message construction, queued/running changes, successive zero-period turns, provider timing, in-flight tick races, disposal and cancellation, callback exceptions, and legacy registration. Shared setup consolidates registration, diagnostics and logging assertions. The complete shared timer fixture also arms readiness observers before triggering work.
This carries the timer repair investigated in #11451 and proposed in #11454 onto the narrowed provider-owned implementation. The configured provider's tick notifications are admitted through the lifecycle state machine, preserving queue-pump progress when timer resolution produces a pre-deadline notification. The investigations retain their individually recorded historical stream failures.
This standalone timer extraction is based on main b3b76e2ab207f00e664e0167cd733800cd60379d. It originated from the timer-only source of #10693 at 9c1ef0f2feb258c1764de5f408d89c53e7e63f9f, extracted using original base 48f3aaa47fc18123db4109063af591f315e6f9cb, and has been narrowed through user-directed state, timing, lifecycle, and review-surface simplification.
The current-main baseline is commit bfe0e81e37 and uses the same reviewed coverage matrix.
Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities.
The comparison remains report-only while normal line and branch variance is calibrated.
This observer is called synchronously on whichever thread emits the diagnostic event, but DisposeDuringCallback_ReentrantFailingCancellationCompletesDisposalOnce can emit Disposed from the disposing thread while the asynchronously resumed callback emits TickStop. Concurrent List<T>.Add calls can corrupt or lose fixture events, making the lifecycle assertions flaky. Serialize writes here (or use a concurrent collection).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Queue immediately due grain timer ticks directly as local-only activation requests instead of routing them through the physical timer. Preserve normal interleaving and keep-alive rules and start a fresh call chain. Delayed timing and resolution remain owned by the configured TimeProvider. Timer messages use the factory's explicit context-free path so ambient request data is neither copied nor mutated; ordinary requests retain their existing context export behavior.
Keep the physical timer eagerly created and readonly. Use one Idle/Busy/Disposed lifecycle, where Busy covers both the queued turn and its running callback. Reserving a turn defaults its following delay to the period; Change replaces that following schedule. A queued callback keeps its turn, and changes while queued or running take effect after it completes, with the latest due time and period winning. This avoids separate queued/running bookkeeping and replacement-arm invalidation.
A small state lock coordinates provider callbacks with grain-side scheduling and runtime disposal. Enqueue local activation messages and run cancellation registrations outside that lock to preserve shutdown ordering. Disposal is terminal before cancellation registrations execute, so queued messages drain and admitted callbacks receive cancellation. Activation enqueueing is a local operation: the timer relies on that guarantee rather than modeling recoverable delivery failure or resetting and re-arming its schedule. The existing boundary logger reports unexpected runtime exceptions; application callback and cancellation-registration exceptions retain their established handling.
The focused tests cover distinct contracts: immediate activation admission, normal versus context-free message construction, queued/running changes, successive zero-period turns, provider timing, in-flight tick races, disposal and cancellation, callback exceptions, and legacy registration. Shared setup consolidates registration, diagnostics and logging assertions. The complete shared timer fixture also arms readiness observers before triggering work.
This carries the timer repair investigated in #11451 and proposed in #11454 onto the narrowed provider-owned implementation. The configured provider's tick notifications are admitted through the lifecycle state machine, preserving queue-pump progress when timer resolution produces a pre-deadline notification. The investigations retain their individually recorded historical stream failures.
This standalone timer extraction is based on main
b3b76e2ab207f00e664e0167cd733800cd60379d. It originated from the timer-only source of #10693 at9c1ef0f2feb258c1764de5f408d89c53e7e63f9f, extracted using original base48f3aaa47fc18123db4109063af591f315e6f9cb, and has been narrowed through user-directed state, timing, lifecycle, and review-surface simplification.Microsoft Reviewers: Open in CodeFlow