Skip to content

Commit 80a5c75

Browse files
Sync changes from main to net8 - Applied recent commits, updated versions & framework, preserved .csproj files (#576)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent d57a274 commit 80a5c75

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

src/Directory.Build.props

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageIcon>icon.jpg</PackageIcon>
1010
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1111
<Version>8.1.0</Version>
12-
<DotNetVersion>[8.0.0,9.0.0)</DotNetVersion>
12+
<DotNetVersion>[10.0.0,11.0.0)</DotNetVersion>
1313
<LangVersion>default</LangVersion>
1414
</PropertyGroup>
1515

@@ -18,5 +18,4 @@
1818
</ItemGroup>
1919

2020
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
21-
2221
</Project>

src/TickerQ.EntityFrameworkCore/Infrastructure/BasePersistenceProvider.cs

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,10 @@ public async Task ReleaseAcquiredTimeTickers(Guid[] timeTickerIds, CancellationT
103103
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
104104
var now = _clock.UtcNow;
105105

106-
var baseQuery = timeTickerIds.Length == 0
106+
var idList = timeTickerIds.ToList();
107+
var baseQuery = idList.Count == 0
107108
? dbContext.Set<TTimeTicker>()
108-
: dbContext.Set<TTimeTicker>().Where(x => timeTickerIds.Contains(x.Id));
109+
: dbContext.Set<TTimeTicker>().Where(x => idList.Contains(x.Id));
109110

110111
await baseQuery
111112
.WhereCanAcquire(_lockHolder)
@@ -127,9 +128,15 @@ public async Task<int> UpdateTimeTicker(InternalFunctionContext functionContexts
127128
public async Task UpdateTimeTickersWithUnifiedContext(Guid[] timeTickerIds, InternalFunctionContext functionContext, CancellationToken cancellationToken = default)
128129
{
129130
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
131+
var idList = timeTickerIds.ToList();
130132
await dbContext.Set<TTimeTicker>()
133+
<<<<<<< HEAD
131134
.Where(x => timeTickerIds.Contains(x.Id))
132135
.ExecuteUpdateAsync(MappingExtensions.UpdateTimeTicker<TTimeTicker>(functionContext, _clock.UtcNow), cancellationToken).ConfigureAwait(false);
136+
=======
137+
.Where(x => idList.Contains(x.Id))
138+
.ExecuteUpdateAsync(setter => setter.UpdateTimeTicker<TTimeTicker>(functionContext, _clock.UtcNow), cancellationToken).ConfigureAwait(false);
139+
>>>>>>> 39b9b90 (Fix .NET 9+ EF Core query failures caused by ReadOnlySpan array.Contains() (#574))
133140
}
134141

135142
public async Task<TimeTickerEntity[]> GetEarliestTimeTickers(CancellationToken cancellationToken)
@@ -214,10 +221,11 @@ public async Task<TimeTickerEntity[]> AcquireImmediateTimeTickersAsync(Guid[] id
214221

215222
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
216223
var now = _clock.UtcNow;
224+
var idList = ids.ToList();
217225

218226
// Acquire and mark InProgress in a single update
219227
var affected = await dbContext.Set<TTimeTicker>()
220-
.Where(x => ids.Contains(x.Id))
228+
.Where(x => idList.Contains(x.Id))
221229
.WhereCanAcquire(_lockHolder)
222230
.ExecuteUpdateAsync(setter => setter
223231
.SetProperty(x => x.LockHolder, _lockHolder)
@@ -232,7 +240,7 @@ public async Task<TimeTickerEntity[]> AcquireImmediateTimeTickersAsync(Guid[] id
232240
// Return the acquired tickers for immediate execution, with children
233241
return await dbContext.Set<TTimeTicker>()
234242
.AsNoTracking()
235-
.Where(x => ids.Contains(x.Id) && x.LockHolder == _lockHolder && x.Status == TickerStatus.InProgress)
243+
.Where(x => idList.Contains(x.Id) && x.LockHolder == _lockHolder && x.Status == TickerStatus.InProgress)
236244
.Include(x => x.Children.Where(y => y.ExecutionTime == null))
237245
.Select(MappingExtensions.ForQueueTimeTickers<TTimeTicker>())
238246
.ToArrayAsync(cancellationToken)
@@ -245,7 +253,7 @@ public async Task MigrateDefinedCronTickers((string Function, string Expression)
245253
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
246254
var now = _clock.UtcNow;
247255

248-
var functions = cronTickers.Select(x => x.Function).ToArray();
256+
var functions = cronTickers.Select(x => x.Function).ToList();
249257
var cronSet = dbContext.Set<TCronTicker>();
250258

251259
// Build the complete set of registered function names to detect orphaned tickers.
@@ -262,16 +270,17 @@ public async Task MigrateDefinedCronTickers((string Function, string Expression)
262270
.ToArrayAsync(cancellationToken)
263271
.ConfigureAwait(false);
264272

265-
if (orphanedCron.Length > 0)
273+
var orphanedCronList = orphanedCron.ToList();
274+
if (orphanedCronList.Count > 0)
266275
{
267276
// Delete related occurrences first (if any), then the cron tickers
268277
await dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
269-
.Where(o => orphanedCron.Contains(o.CronTickerId))
278+
.Where(o => orphanedCronList.Contains(o.CronTickerId))
270279
.ExecuteDeleteAsync(cancellationToken)
271280
.ConfigureAwait(false);
272281

273282
await cronSet
274-
.Where(c => orphanedCron.Contains(c.Id))
283+
.Where(c => orphanedCronList.Contains(c.Id))
275284
.ExecuteDeleteAsync(cancellationToken)
276285
.ConfigureAwait(false);
277286
}
@@ -421,9 +430,10 @@ public async Task ReleaseAcquiredCronTickerOccurrences(Guid[] occurrenceIds, Can
421430
var now = _clock.UtcNow;
422431
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
423432

424-
var baseQuery = occurrenceIds.Length == 0
425-
? dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
426-
: dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>().Where(x => occurrenceIds.Contains(x.Id));
433+
var idList = occurrenceIds.ToList();
434+
var baseQuery = idList.Count == 0
435+
? dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
436+
: dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>().Where(x => idList.Contains(x.Id));
427437

428438
await baseQuery
429439
.WhereCanAcquire(_lockHolder)
@@ -524,13 +534,23 @@ public async IAsyncEnumerable<CronTickerOccurrenceEntity<TCronTicker>> QueueCron
524534
public async Task<CronTickerOccurrenceEntity<TCronTicker>> GetEarliestAvailableCronOccurrence(Guid[] ids, CancellationToken cancellationToken = default)
525535
{
526536
var now = _clock.UtcNow;
537+
<<<<<<< HEAD
527538
var mainSchedulerThreshold = now.AddMilliseconds(-now.Millisecond);
539+
=======
540+
var mainSchedulerThreshold = now.AddSeconds(-1);
541+
var idList = ids.ToList();
542+
>>>>>>> 39b9b90 (Fix .NET 9+ EF Core query failures caused by ReadOnlySpan array.Contains() (#574))
528543
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
529544
return await dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
530545
.AsNoTracking()
531546
.Include(x => x.CronTicker)
547+
<<<<<<< HEAD
532548
.Where(x => ids.Contains(x.CronTickerId))
533549
.Where(x => x.ExecutionTime >= mainSchedulerThreshold) // Only recent/upcoming tasks (not heavily overdue)
550+
=======
551+
.Where(x => idList.Contains(x.CronTickerId))
552+
.Where(x => x.ExecutionTime >= mainSchedulerThreshold) // Only items within the 1-second main scheduler window
553+
>>>>>>> 39b9b90 (Fix .NET 9+ EF Core query failures caused by ReadOnlySpan array.Contains() (#574))
534554
.WhereCanAcquire(_lockHolder)
535555
.OrderBy(x => x.ExecutionTime)
536556
.Select(MappingExtensions.ForLatestQueuedCronTickerOccurrence<CronTickerOccurrenceEntity<TCronTicker>, TCronTicker>())
@@ -554,9 +574,15 @@ public async Task UpdateCronTickerOccurrencesWithUnifiedContext(Guid[] cronOccur
554574
CancellationToken cancellationToken = default)
555575
{
556576
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
577+
var idList = cronOccurrenceIds.ToList();
557578
await dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
579+
<<<<<<< HEAD
558580
.Where(x => cronOccurrenceIds.Contains(x.Id))
559581
.ExecuteUpdateAsync(MappingExtensions.UpdateCronTickerOccurrence<TCronTicker>(functionContext), cancellationToken)
582+
=======
583+
.Where(x => idList.Contains(x.Id))
584+
.ExecuteUpdateAsync(setter => setter.UpdateCronTickerOccurrence<TCronTicker>(functionContext), cancellationToken)
585+
>>>>>>> 39b9b90 (Fix .NET 9+ EF Core query failures caused by ReadOnlySpan array.Contains() (#574))
560586
.ConfigureAwait(false);
561587
}
562588

src/TickerQ.EntityFrameworkCore/Infrastructure/TickerEFCorePersistenceProvider.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,11 @@ public async Task<int> RemoveTimeTickers(Guid[] timeTickerIds, CancellationToken
101101
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);;
102102

103103
// Load the entities to be deleted (including children for cascade delete)
104+
var idList = timeTickerIds.ToList();
104105
var tickersToDelete = await dbContext.Set<TTimeTicker>()
105106
.Include(x => x.Children)
106107
.ThenInclude(x => x.Children) // Include grandchildren if needed
107-
.Where(x => timeTickerIds.Contains(x.Id))
108+
.Where(x => idList.Contains(x.Id))
108109
.ToListAsync(cancellationToken)
109110
.ConfigureAwait(false);
110111

@@ -189,7 +190,8 @@ public async Task<int> UpdateCronTickers(TCronTicker[] cronTickers, Cancellation
189190
public async Task<int> RemoveCronTickers(Guid[] cronTickerIds, CancellationToken cancellationToken)
190191
{
191192
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
192-
var result = await dbContext.Set<TCronTicker>().Where(x => cronTickerIds.Contains(x.Id))
193+
var idList = cronTickerIds.ToList();
194+
var result = await dbContext.Set<TCronTicker>().Where(x => idList.Contains(x.Id))
193195
.ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
194196

195197
if(RedisContext.HasRedisConnection)
@@ -246,8 +248,9 @@ public async Task<int> InsertCronTickerOccurrences(CronTickerOccurrenceEntity<TC
246248
public async Task<int> RemoveCronTickerOccurrences(Guid[] cronTickerOccurrences, CancellationToken cancellationToken = default)
247249
{
248250
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
251+
var idList = cronTickerOccurrences.ToList();
249252
return await dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
250-
.Where(x => cronTickerOccurrences.Contains(x.Id))
253+
.Where(x => idList.Contains(x.Id))
251254
.ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
252255
}
253256

@@ -258,10 +261,11 @@ public async Task<CronTickerOccurrenceEntity<TCronTicker>[]> AcquireImmediateCro
258261

259262
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
260263
var now = _clock.UtcNow;
264+
var idList = occurrenceIds.ToList();
261265

262266
// Only acquire occurrences that are acquirable (Idle/Queued and not locked by another node)
263267
var query = dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
264-
.Where(x => occurrenceIds.Contains(x.Id))
268+
.Where(x => idList.Contains(x.Id))
265269
.WhereCanAcquire(_lockHolder);
266270

267271
// Lock and mark InProgress
@@ -279,7 +283,7 @@ public async Task<CronTickerOccurrenceEntity<TCronTicker>[]> AcquireImmediateCro
279283
// Return acquired occurrences with CronTicker populated
280284
return await dbContext.Set<CronTickerOccurrenceEntity<TCronTicker>>()
281285
.AsNoTracking()
282-
.Where(x => occurrenceIds.Contains(x.Id) && x.LockHolder == _lockHolder && x.Status == TickerStatus.InProgress)
286+
.Where(x => idList.Contains(x.Id) && x.LockHolder == _lockHolder && x.Status == TickerStatus.InProgress)
283287
.Include(x => x.CronTicker)
284288
.ToArrayAsync(cancellationToken)
285289
.ConfigureAwait(false);

0 commit comments

Comments
 (0)