@@ -81,13 +81,13 @@ public async IAsyncEnumerable<TimeTickerEntity> QueueTimeTickers(TimeTickerEntit
8181 public async IAsyncEnumerable < TimeTickerEntity > QueueTimedOutTimeTickers ( [ EnumeratorCancellation ] CancellationToken cancellationToken = default )
8282 {
8383 var now = _clock . UtcNow ;
84- var fallbackThreshold = now . AddMilliseconds ( - 100 ) ; // Fallback picks up tasks overdue by > 100ms
84+ var fallbackThreshold = now . AddSeconds ( - 1 ) ; // Fallback picks up tasks older than main 1-second window
8585
8686 // First, get the time tickers that need to be updated (matching EF query)
8787 var timeTickersToUpdate = TimeTickers . Values
8888 . Where ( x => x . ExecutionTime != null )
8989 . Where ( x => x . Status == TickerStatus . Idle || x . Status == TickerStatus . Queued )
90- . Where ( x => x . ExecutionTime <= fallbackThreshold ) // Only tasks overdue by more than 100ms
90+ . Where ( x => x . ExecutionTime <= fallbackThreshold ) // Only tasks older than 1 second
9191 . Select ( x => ForQueueTimeTickers ( x ) ) // Map to TimeTickerEntity with children, matching EF's Select
9292 . ToArray ( ) ;
9393
@@ -149,13 +149,15 @@ public Task ReleaseAcquiredTimeTickers(Guid[] timeTickerIds, CancellationToken c
149149 public Task < TimeTickerEntity [ ] > GetEarliestTimeTickers ( CancellationToken cancellationToken = default )
150150 {
151151 var now = _clock . UtcNow ;
152- var mainSchedulerThreshold = now . AddMilliseconds ( - 100 ) ; // Main scheduler handles tasks up to 100ms overdue
152+
153+ // Define the window: ignore anything older than 1 second ago
154+ var oneSecondAgo = now . AddSeconds ( - 1 ) ;
153155
154156 // Build base query matching EF Core's approach
155157 var baseQuery = TimeTickers . Values
156158 . Where ( x => x . ExecutionTime != null )
157159 . Where ( CanAcquire )
158- . Where ( x => x . ExecutionTime >= mainSchedulerThreshold ) ; // Only recent/upcoming tasks (not heavily overdue )
160+ . Where ( x => x . ExecutionTime >= oneSecondAgo ) ; // Ignore old tickers (fallback handles them )
159161
160162 // Get minimum execution time (matching EF's approach)
161163 var minExecutionTime = baseQuery
@@ -166,12 +168,22 @@ public Task<TimeTickerEntity[]> GetEarliestTimeTickers(CancellationToken cancell
166168 if ( minExecutionTime == null )
167169 return Task . FromResult ( Array . Empty < TimeTickerEntity > ( ) ) ;
168170
169- // Get tasks within 50ms window of the earliest task for batching efficiency
170- var batchWindow = minExecutionTime . Value . AddMilliseconds ( 50 ) ;
171+ // Round the minimum execution time down to its second
172+ var minSecond = new DateTime (
173+ minExecutionTime . Value . Year ,
174+ minExecutionTime . Value . Month ,
175+ minExecutionTime . Value . Day ,
176+ minExecutionTime . Value . Hour ,
177+ minExecutionTime . Value . Minute ,
178+ minExecutionTime . Value . Second ,
179+ DateTimeKind . Utc ) ;
180+
181+ // Fetch all tickers within that complete second (this ensures we get all tickers in the same second)
182+ var maxExecutionTime = minSecond . AddSeconds ( 1 ) ;
171183
172- // Final query with mapping (matching EF's approach)
173184 var result = baseQuery
174- . Where ( x => x . ExecutionTime . Value <= batchWindow )
185+ . Where ( x => x . ExecutionTime >= minSecond && x . ExecutionTime < maxExecutionTime )
186+ . OrderBy ( x => x . ExecutionTime )
175187 . Select ( ForQueueTimeTickers ) // Use same mapping as EF Core
176188 . ToArray ( ) ;
177189
@@ -598,7 +610,7 @@ public Task<int> RemoveCronTickers(Guid[] cronTickerIds, CancellationToken cance
598610 public Task < CronTickerOccurrenceEntity < TCronTicker > > GetEarliestAvailableCronOccurrence ( Guid [ ] ids , CancellationToken cancellationToken = default )
599611 {
600612 var now = _clock . UtcNow ;
601- var mainSchedulerThreshold = now . AddMilliseconds ( - 100 ) ; // Main scheduler handles tasks up to 100ms overdue
613+ var mainSchedulerThreshold = now . AddSeconds ( - 1 ) ; // Main scheduler handles items within the 1-second window
602614
603615 var query = CronOccurrences . Values . AsEnumerable ( ) ;
604616
@@ -673,11 +685,11 @@ public async IAsyncEnumerable<CronTickerOccurrenceEntity<TCronTicker>> QueueCron
673685 public async IAsyncEnumerable < CronTickerOccurrenceEntity < TCronTicker > > QueueTimedOutCronTickerOccurrences ( [ EnumeratorCancellation ] CancellationToken cancellationToken = default )
674686 {
675687 var now = _clock . UtcNow ;
676- var fallbackThreshold = now . AddMilliseconds ( - 100 ) ; // Fallback picks up tasks overdue by > 100ms
688+ var fallbackThreshold = now . AddSeconds ( - 1 ) ; // Fallback picks up tasks older than main 1-second window
677689
678690 var occurrencesToUpdate = CronOccurrences . Values
679691 . Where ( x => x . Status == TickerStatus . Idle || x . Status == TickerStatus . Queued )
680- . Where ( x => x . ExecutionTime <= fallbackThreshold ) // Only tasks overdue by more than 100ms
692+ . Where ( x => x . ExecutionTime <= fallbackThreshold ) // Only tasks older than 1 second
681693 . ToArray ( ) ;
682694
683695 foreach ( var occurrence in occurrencesToUpdate )
@@ -1004,4 +1016,4 @@ private void ApplyFunctionContextToCronOccurrence(CronTickerOccurrenceEntity<TCr
10041016
10051017 #endregion
10061018 }
1007- }
1019+ }
0 commit comments