Public Access
28 lines
1.2 KiB
C#
28 lines
1.2 KiB
C#
using DodoSSH.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace DodoSSH.Api.Features.Teams;
|
|
|
|
/// <summary>
|
|
/// Serialises the writes that decide what a team owns, for the life of the transaction.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Archiving a team refuses while it owns a vault, and creating a vault refuses on an archived team — but each
|
|
/// used to check outside any transaction the other could see, so the two could pass each other: the archive
|
|
/// counted no vaults, a create landed a moment later, and the team was archived with a live vault in it that
|
|
/// nobody could reach. Both now take this lock inside their transaction and check again under it.
|
|
/// </para>
|
|
/// <para>
|
|
/// The same advisory lock the sync push takes per vault, keyed apart so a team and a vault never share one.
|
|
/// Requires <c>Multiplexing=false</c> on the connection, as that one does.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal static class TeamLock
|
|
{
|
|
internal static Task<int> AcquireAsync(DodoDbContext database, Guid teamId, CancellationToken cancellationToken) =>
|
|
database.Database.ExecuteSqlAsync(
|
|
$"SELECT pg_advisory_xact_lock(hashtextextended({"team:" + teamId.ToString()}, 0))",
|
|
cancellationToken);
|
|
}
|