fix: make default initialization concurrency-safe
This commit is contained in:
@@ -27,13 +27,7 @@ namespace JobTrackerApi.Controllers
|
||||
// Per-user rule settings when authenticated.
|
||||
if (!string.IsNullOrWhiteSpace(_db.CurrentUserId))
|
||||
{
|
||||
var u = await _db.UserRuleSettings.FirstOrDefaultAsync(x => x.OwnerUserId == _db.CurrentUserId, cancellationToken);
|
||||
if (u is null)
|
||||
{
|
||||
u = new UserRuleSettings { OwnerUserId = _db.CurrentUserId };
|
||||
_db.UserRuleSettings.Add(u);
|
||||
await _db.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
var u = await GetOrCreateUserSettingsAsync(_db.CurrentUserId, cancellationToken);
|
||||
|
||||
return Ok(new RuleSettings
|
||||
{
|
||||
@@ -64,12 +58,7 @@ namespace JobTrackerApi.Controllers
|
||||
// Per-user rule settings when authenticated.
|
||||
if (!string.IsNullOrWhiteSpace(_db.CurrentUserId))
|
||||
{
|
||||
var s = await _db.UserRuleSettings.FirstOrDefaultAsync(x => x.OwnerUserId == _db.CurrentUserId, cancellationToken);
|
||||
if (s is null)
|
||||
{
|
||||
s = new UserRuleSettings { OwnerUserId = _db.CurrentUserId };
|
||||
_db.UserRuleSettings.Add(s);
|
||||
}
|
||||
var s = await GetOrCreateUserSettingsAsync(_db.CurrentUserId, cancellationToken);
|
||||
|
||||
s.AppliedFollowUpDays = Clamp(incoming.AppliedFollowUpDays, 1, 365);
|
||||
s.AppliedGhostDays = Clamp(incoming.AppliedGhostDays, 1, 365);
|
||||
@@ -101,6 +90,27 @@ namespace JobTrackerApi.Controllers
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private async Task<UserRuleSettings> GetOrCreateUserSettingsAsync(string ownerUserId, CancellationToken cancellationToken)
|
||||
{
|
||||
var settings = await _db.UserRuleSettings.FirstOrDefaultAsync(x => x.OwnerUserId == ownerUserId, cancellationToken);
|
||||
if (settings is not null) return settings;
|
||||
|
||||
settings = new UserRuleSettings { OwnerUserId = ownerUserId };
|
||||
_db.UserRuleSettings.Add(settings);
|
||||
try
|
||||
{
|
||||
await _db.SaveChangesAsync(cancellationToken);
|
||||
return settings;
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
_db.Entry(settings).State = EntityState.Detached;
|
||||
settings = await _db.UserRuleSettings.FirstOrDefaultAsync(x => x.OwnerUserId == ownerUserId, cancellationToken);
|
||||
if (settings is null) throw;
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
private static int Clamp(int v, int min, int max) => v < min ? min : v > max ? max : v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,6 +357,7 @@ public sealed class ApplicationChecklistService : IApplicationChecklistService
|
||||
var missing = Defaults.Where(t => !existing.Contains(t.Key)).ToList();
|
||||
if (missing.Count == 0) return items;
|
||||
|
||||
var seeded = new List<ApplicationChecklistItem>(missing.Count);
|
||||
var order = 0;
|
||||
foreach (var template in Defaults)
|
||||
{
|
||||
@@ -377,12 +378,27 @@ public sealed class ApplicationChecklistService : IApplicationChecklistService
|
||||
};
|
||||
_db.ApplicationChecklistItems.Add(item);
|
||||
items.Add(item);
|
||||
seeded.Add(item);
|
||||
}
|
||||
order++;
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync(ct);
|
||||
return items;
|
||||
try
|
||||
{
|
||||
await _db.SaveChangesAsync(ct);
|
||||
return items;
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
foreach (var item in seeded) _db.Entry(item).State = EntityState.Detached;
|
||||
|
||||
var persisted = await LoadItemsAsync(ownerUserId, jobApplicationId, ct);
|
||||
var persistedKeys = persisted.Where(i => i.SystemKey is not null)
|
||||
.Select(i => i.SystemKey!)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
if (missing.Any(template => !persistedKeys.Contains(template.Key))) throw;
|
||||
return persisted;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SyncAutoCompletionAsync(List<ApplicationChecklistItem> items, ChecklistSignals signals, CancellationToken ct)
|
||||
|
||||
Reference in New Issue
Block a user