fix: make default initialization concurrency-safe

This commit is contained in:
cesnimda
2026-09-22 07:33:51 +02:00
parent 38cf37ef96
commit 57a6bd02c6
4 changed files with 187 additions and 15 deletions
+23 -13
View File
@@ -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;
}
}