Skip to content

Commit

Permalink
#124 Unique constraint violations are not propagated
Browse files Browse the repository at this point in the history
  • Loading branch information
threbicek-te authored and wassim-k committed Mar 24, 2023
1 parent ac9f860 commit ccf398f
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Orleans.Providers.MongoDB/Orleans.Providers.MongoDB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageTags>Orleans OrleansProviders MongoDB</PackageTags>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TargetFrameworks>net7.0</TargetFrameworks>
<Version>7.4.0</Version>
<Version>7.5.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 7 additions & 2 deletions Orleans.Providers.MongoDB/Utils/MongoExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MongoDB.Driver;
using System;
using MongoDB.Driver;
using Orleans.Providers.MongoDB.Configuration;

namespace Orleans.Providers.MongoDB.Utils
Expand All @@ -11,10 +12,14 @@ public static bool IsDuplicateKey(this MongoException ex)
{
return true;
}
if (ex is MongoWriteException w && w.WriteError.Category == ServerErrorCategory.DuplicateKey)

if (ex is MongoWriteException w
&& w.WriteError.Category == ServerErrorCategory.DuplicateKey
&& w.WriteError.Message.Contains("index: _id_ ", StringComparison.Ordinal))
{
return true;
}

return false;
}

Expand Down
9 changes: 9 additions & 0 deletions Test/GrainInterfaces/IConstrainedGrain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;

namespace Orleans.Providers.MongoDB.Test.GrainInterfaces
{
public interface IConstrainedGrain : IGrainWithIntegerKey
{
Task SetName(string name);
}
}
31 changes: 31 additions & 0 deletions Test/Grains/ConstrainedGrain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
using Orleans.Providers.MongoDB.Test.GrainInterfaces;
using Orleans.Runtime;

namespace Orleans.Providers.MongoDB.Test.Grains
{
internal class ConstrainedGrain : Grain, IConstrainedGrain
{
private readonly IPersistentState<ConstrainedGrainState> state;

public ConstrainedGrain([PersistentState(nameof(ConstrainedGrain), "MongoDBStore")] IPersistentState<ConstrainedGrainState> state)
{
this.state = state;
}

public async Task SetName(string name)
{
state.State.Name = name;

try
{
await state.WriteStateAsync();
}
catch (Exception ex)
{
throw new ProviderStateException(ex.Message);
}
}
}
}
7 changes: 7 additions & 0 deletions Test/Grains/ConstrainedGrainState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Orleans.Providers.MongoDB.Test.Grains
{
public class ConstrainedGrainState
{
public string Name { get; set; }
}
}
58 changes: 58 additions & 0 deletions Test/Host/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using Newtonsoft.Json;
using Orleans.Configuration;
using Orleans.Hosting;
using Orleans.Providers.MongoDB.Configuration;
using Orleans.Providers.MongoDB.StorageProviders.Serializers;
using Orleans.Providers.MongoDB.Test.GrainInterfaces;
using Orleans.Providers.MongoDB.Test.Grains;
using Orleans.Runtime;

namespace Orleans.Providers.MongoDB.Test.Host
Expand Down Expand Up @@ -87,6 +89,8 @@ public static async Task Main(string[] args)

await host.StartAsync();

await CreateConstraints(host.Services.GetRequiredService<IMongoClient>());

var clientHost = new HostBuilder()
.UseOrleansClient((ctx, clientBuilder) => clientBuilder
.UseMongoDBClient(mongoRunner.ConnectionString)
Expand Down Expand Up @@ -121,11 +125,30 @@ public static async Task Main(string[] args)
await TestState(client);
await TestStateWithCollections(client);

await TestStateConstraints(client);

Console.ReadKey();

await host.StopAsync();
}

private static async Task CreateConstraints(IMongoClient mongoClient)
{
var collection = mongoClient.GetDatabase("OrleansTestApp")
.GetCollection<ConstrainedGrainState>("GrainsConstrainedGrain");

var indexBuilder = Builders<ConstrainedGrainState>.IndexKeys.Ascending(f => f.Name);

var options = new CreateIndexOptions
{
Unique = true
};

var indexModel = new CreateIndexModel<ConstrainedGrainState>(indexBuilder, options);

await collection.Indexes.CreateOneAsync(indexModel);
}

private static async Task TestStreams(IClusterClient client)
{
var streamProducer = client.GetGrain<IStreamProducerGrain>(0);
Expand Down Expand Up @@ -205,6 +228,41 @@ private static async Task TestState(IClusterClient client)

Console.WriteLine(employeeId);
}

private static async Task TestStateConstraints(IClusterClient client)
{
var database = client.ServiceProvider.GetRequiredService<IMongoClient>()
.GetDatabase("OrleansTestApp");

var guid = Guid.NewGuid().ToString();

var grain0 = client.GetGrain<IConstrainedGrain>(0);
await grain0.SetName(guid);

var filter = Builders<BsonDocument>.Filter.Eq("_id", "constrained/0");
var update = Builders<BsonDocument>.Update.Set("_etag", Guid.NewGuid().ToString());

await database.GetCollection<BsonDocument>("GrainsConstrainedGrain").UpdateOneAsync(filter, update);

try
{
await grain0.SetName(Guid.NewGuid().ToString());
}
catch (ProviderStateException ex)
{
Console.WriteLine($"Exception thrown due to invalid e-tag: {ex.Message}");
}

var grain1 = client.GetGrain<IConstrainedGrain>(1);
try
{
await grain1.SetName(guid);
}
catch (ProviderStateException ex)
{
Console.WriteLine($"Exception thrown due to unique constrain violation: {ex.Message}");
}
}

private static void ApplyBsonConfiguration()
{
Expand Down

0 comments on commit ccf398f

Please sign in to comment.