diff --git a/src/AppCoreNet.EventStore.SqlServer/SqlServerEventStore.cs b/src/AppCoreNet.EventStore.SqlServer/SqlServerEventStore.cs index 90f894f..03535f7 100644 --- a/src/AppCoreNet.EventStore.SqlServer/SqlServerEventStore.cs +++ b/src/AppCoreNet.EventStore.SqlServer/SqlServerEventStore.cs @@ -1,4 +1,4 @@ -// Licensed under the MIT license. +// Licensed under the MIT license. // Copyright (c) The AppCore .NET project. using System; @@ -62,6 +62,7 @@ public async Task WriteAsync( StreamId = streamId, ExpectedPosition = state.Value, Events = events, + LockResource = _options.ApplicationName + "-WriteEvents", }; Model.WriteEventsResult result = diff --git a/src/AppCoreNet.EventStore.SqlServer/WriteEventsStoredProcedure.cs b/src/AppCoreNet.EventStore.SqlServer/WriteEventsStoredProcedure.cs index d2665b1..51d97a0 100644 --- a/src/AppCoreNet.EventStore.SqlServer/WriteEventsStoredProcedure.cs +++ b/src/AppCoreNet.EventStore.SqlServer/WriteEventsStoredProcedure.cs @@ -1,4 +1,4 @@ -// Licensed under the MIT license. +// Licensed under the MIT license. // Copyright (c) The AppCore .NET project. using System; @@ -24,6 +24,8 @@ internal sealed class WriteEventsSqlStoredProcedure : SqlStoredProcedure Events { get; init; } + required public string LockResource { get; init; } + public WriteEventsSqlStoredProcedure(DbContext dbContext, string? schema, IEventStoreSerializer serializer) : base(dbContext, $"[{SchemaUtils.GetEventStoreSchema(schema)}].{ProcedureName}") { @@ -51,16 +53,21 @@ public static IEnumerable GetCreateScripts(string? schema) CREATE PROCEDURE [{schema}].{ProcedureName} ( @{nameof(StreamId)} NVARCHAR({Constants.StreamIdMaxLength}), @{nameof(ExpectedPosition)} BIGINT, - @{nameof(Events)} [{schema}].[{nameof(Model.EventTableType)}] READONLY + @{nameof(Events)} [{schema}].[{nameof(Model.EventTableType)}] READONLY, + @{nameof(LockResource)} NVARCHAR(max) ) AS BEGIN DECLARE @StreamKey AS INT; DECLARE @StreamSequence AS BIGINT; DECLARE @StreamIndex AS BIGINT; + DECLARE @LockResult AS INT; IF @{nameof(StreamId)} is NULL RAISERROR('The value for parameter ''{nameof(StreamId)}'' must not be NULL', 16, 1) + EXEC @LockResult = sp_getapplock @Resource = @{nameof(LockResource)}, @LockMode = 'Exclusive'; + IF @LockResult < 0 RAISERROR('Event write lock could not be acquired', 16, 1) + SELECT @StreamKey = Id, @StreamSequence = [{nameof(Model.EventStream.Sequence)}], @@ -192,6 +199,7 @@ protected override SqlParameter[] GetParameters() TypeName = $"[{_schema}].[{nameof(Model.EventTableType)}]", Value = CreateEventDataTable(), }, + new SqlParameter($"@{nameof(LockResource)}", LockResource) ]; } } \ No newline at end of file