Skip to content

Commit 5a46f6a

Browse files
committed
Fix relational EF claim concurrency
1 parent 6e36359 commit 5a46f6a

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

src/Mule.EntityFrameworkCore/EntityFrameworkMuleStorage.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ public async Task<IReadOnlyCollection<DurableAction>> ClaimPendingAsync(
116116
if (IsSqlServer())
117117
return await ClaimSqlServerAsync(lane, batchSize, lockExpiration, now, cancellationToken);
118118

119+
if (_dbContext.Database.IsRelational())
120+
return await ClaimRelationalAsync(lane, batchSize, lockExpiration, now, cancellationToken);
121+
119122
return await ClaimTrackedAsync(lane, batchSize, lockExpiration, now, cancellationToken);
120123
}
121124

@@ -188,6 +191,58 @@ private async Task<IReadOnlyCollection<DurableAction>> ClaimTrackedAsync(
188191
return candidates.ToArray();
189192
}
190193

194+
private async Task<IReadOnlyCollection<DurableAction>> ClaimRelationalAsync(
195+
string lane,
196+
int batchSize,
197+
DateTimeOffset lockExpiration,
198+
DateTimeOffset now,
199+
CancellationToken cancellationToken)
200+
{
201+
var normalizedLane = NormalizeLane(lane);
202+
var candidates = await Actions
203+
.AsNoTracking()
204+
.Where(x =>
205+
x.Lane == normalizedLane &&
206+
(x.Status == DurableActionStatus.Pending || x.Status == DurableActionStatus.Locked))
207+
.Select(x => new
208+
{
209+
x.Id,
210+
x.Status,
211+
x.CreatedOnUtc,
212+
x.LockedOnUtc,
213+
x.NextAttemptOnUtc
214+
})
215+
.ToListAsync(cancellationToken);
216+
217+
var candidateIds = candidates
218+
.Where(x =>
219+
x.Status == DurableActionStatus.Pending && (x.NextAttemptOnUtc == null || x.NextAttemptOnUtc <= now) ||
220+
x.Status == DurableActionStatus.Locked && x.LockedOnUtc <= lockExpiration)
221+
.OrderBy(x => x.NextAttemptOnUtc ?? x.CreatedOnUtc)
222+
.ThenBy(x => x.CreatedOnUtc)
223+
.Select(x => x.Id)
224+
.Take(batchSize)
225+
.ToArray();
226+
227+
if (candidateIds.Length == 0)
228+
return Array.Empty<DurableAction>();
229+
230+
var claimed = new List<DurableAction>(candidateIds.Length);
231+
foreach (var id in candidateIds)
232+
{
233+
var locked = await LockRelationalAsync(id, lockExpiration, now, cancellationToken);
234+
if (locked == 0)
235+
continue;
236+
237+
var action = await Actions
238+
.AsNoTracking()
239+
.SingleAsync(x => x.Id == id, cancellationToken);
240+
claimed.Add(action);
241+
}
242+
243+
return claimed;
244+
}
245+
191246
public async Task MarkCompletedAsync(Guid id, DateTimeOffset completedOnUtc, CancellationToken cancellationToken = default)
192247
{
193248
if (IsSqlServer())

0 commit comments

Comments
 (0)