diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs
new file mode 100644
index 000000000..78c8707fd
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs
@@ -0,0 +1,14 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace Elsa.EntityFrameworkCore.Common.Contracts;
+
+/// Defines the contract for an exception handler in a database context.
+///
+/// Implementing this interface allows for customized handling of exceptions that occur during database operations.
+/// The parameter is used to be able to inject different ExceptionHandlers for each DbContext.
+///
+public interface IDbExceptionHandler where TDbContext : DbContext
+{
+ /// Handles the given exception that occurs during database operations.
+ public void Handle(DbUpdateException exception);
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs b/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs
index d97a47a06..1097da421 100644
--- a/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs
@@ -1,4 +1,5 @@
using Elsa.Common.Entities;
+using Elsa.EntityFrameworkCore.Common.Contracts;
using Microsoft.EntityFrameworkCore;
namespace Elsa.EntityFrameworkCore.Common;
@@ -8,13 +9,9 @@ namespace Elsa.EntityFrameworkCore.Common;
///
/// The type of the database context.
/// The type of the entity.
-public class EntityStore : Store where TDbContext : DbContext where TEntity : Entity, new()
+public class EntityStore(IDbContextFactory dbContextFactory, IDbExceptionHandler exceptionHandler)
+ : Store(dbContextFactory, exceptionHandler) where TDbContext : DbContext where TEntity : Entity, new()
{
- ///
- public EntityStore(IDbContextFactory dbContextFactory) : base(dbContextFactory)
- {
- }
-
///
/// Saves the entity.
///
diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs b/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs
index 622bb773d..c1fbdf658 100644
--- a/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs
@@ -1,6 +1,7 @@
using System.Linq.Expressions;
using Elsa.Common.Entities;
using Elsa.Common.Models;
+using Elsa.EntityFrameworkCore.Common.Contracts;
using Elsa.EntityFrameworkCore.Extensions;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
@@ -14,28 +15,18 @@ namespace Elsa.EntityFrameworkCore.Common;
/// The type of the database context.
/// The type of the entity.
[PublicAPI]
-public class Store where TDbContext : DbContext where TEntity : class, new()
+public class Store(IDbContextFactory dbContextFactory, IDbExceptionHandler exceptionHandler) where TDbContext : DbContext where TEntity : class, new()
{
// ReSharper disable once StaticMemberInGenericType
// Justification: This is a static member that is used to ensure that only one thread can access the database for TEntity at a time.
private static readonly SemaphoreSlim Semaphore = new(1, 1);
- private readonly IDbContextFactory _dbContextFactory;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public Store(IDbContextFactory dbContextFactory)
- {
- _dbContextFactory = dbContextFactory;
- }
-
///
/// Creates a new instance of the database context.
///
/// The cancellation token.
/// The database context.
- public async Task CreateDbContextAsync(CancellationToken cancellationToken = default) => await _dbContextFactory.CreateDbContextAsync(cancellationToken);
+ public async Task CreateDbContextAsync(CancellationToken cancellationToken = default) => await dbContextFactory.CreateDbContextAsync(cancellationToken);
///
/// Adds the specified entity.
@@ -132,6 +123,10 @@ public class Store where TDbContext : DbContext where TEnti
set.Entry(entity).State = exists ? EntityState.Modified : EntityState.Added;
await dbContext.SaveChangesAsync(cancellationToken);
}
+ catch (DbUpdateException ex)
+ {
+ exceptionHandler.Handle(ex);
+ }
finally
{
Semaphore.Release();
@@ -168,7 +163,14 @@ public class Store where TDbContext : DbContext where TEnti
await Task.WhenAll(savingTasks);
}
- await dbContext.BulkUpsertAsync(entityList, keySelector, cancellationToken);
+ try
+ {
+ await dbContext.BulkUpsertAsync(entityList, keySelector, cancellationToken);
+ }
+ catch (DbUpdateException ex)
+ {
+ exceptionHandler.Handle(ex);
+ }
}
///
diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs
index 3bfee3284..064912eb0 100644
--- a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs
+++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs
@@ -5,6 +5,7 @@ using Elsa.EntityFrameworkCore.Modules.Identity;
using Elsa.EntityFrameworkCore.Modules.Labels;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
+using Elsa.EntityFrameworkCore.PostgreSql.Handlers;
// ReSharper disable once CheckNamespace
namespace Elsa.EntityFrameworkCore.Extensions;
@@ -22,6 +23,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreIdentityPersistenceFeature UsePostgreSql(this EFCoreIdentityPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -31,6 +33,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreAlterationsPersistenceFeature UsePostgreSql(this EFCoreAlterationsPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -40,6 +43,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreLabelPersistenceFeature UsePostgreSql(this EFCoreLabelPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -49,6 +53,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreWorkflowDefinitionPersistenceFeature UsePostgreSql(this EFCoreWorkflowDefinitionPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -58,6 +63,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreWorkflowInstancePersistenceFeature UsePostgreSql(this EFCoreWorkflowInstancePersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -67,6 +73,7 @@ public static class PostgreSqlProvidersExtensions
public static WorkflowManagementPersistenceFeature UsePostgreSql(this WorkflowManagementPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
@@ -76,6 +83,7 @@ public static class PostgreSqlProvidersExtensions
public static EFCoreWorkflowRuntimePersistenceFeature UsePostgreSql(this EFCoreWorkflowRuntimePersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default)
{
feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options);
+ feature.DbExceptionHandler = _ => new DbExceptionHandler();
return feature;
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs
new file mode 100644
index 000000000..f23150beb
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs
@@ -0,0 +1,29 @@
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Modules.Alterations;
+using Elsa.EntityFrameworkCore.Modules.Identity;
+using Elsa.EntityFrameworkCore.Modules.Labels;
+using Elsa.EntityFrameworkCore.Modules.Management;
+using Elsa.EntityFrameworkCore.Modules.Runtime;
+using Elsa.Workflows.Exceptions;
+using Microsoft.EntityFrameworkCore;
+using Npgsql;
+
+namespace Elsa.EntityFrameworkCore.PostgreSql.Handlers;
+
+///
+/// Handles database exceptions encountered when using a postgreSQL database.
+///
+public class DbExceptionHandler : IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler
+{
+ /// Handles database exceptions encountered when using a postgreSQL database.
+ public void Handle(DbUpdateException exception)
+ {
+ var ex = exception.InnerException as PostgresException;
+
+ throw new DataProcessingException(ex?.SqlState == "23505", "Unable to save data", exception);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs
new file mode 100644
index 000000000..7fb04ecb7
--- /dev/null
+++ b/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs
@@ -0,0 +1,23 @@
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Modules.Alterations;
+using Elsa.EntityFrameworkCore.Modules.Identity;
+using Elsa.EntityFrameworkCore.Modules.Labels;
+using Elsa.EntityFrameworkCore.Modules.Management;
+using Elsa.EntityFrameworkCore.Modules.Runtime;
+using Microsoft.EntityFrameworkCore;
+
+namespace Elsa.EntityFrameworkCore.Handlers;
+
+/// A No-Op database exception handler.
+public class NoopDbExceptionHandler : IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler,
+ IDbExceptionHandler
+{
+ /// Handles the given exception that occurs during database operations.
+ public void Handle(DbUpdateException exception)
+ {
+ throw exception;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs
index 5a66c8fb4..d2d18bcd7 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs
@@ -1,6 +1,8 @@
using Elsa.Alterations.Core.Entities;
using Elsa.Alterations.Features;
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Microsoft.Extensions.DependencyInjection;
@@ -11,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Alterations;
/// Configures the default workflow runtime to use EF Core persistence providers.
///
[DependsOn(typeof(AlterationsFeature))]
-public class EFCoreAlterationsPersistenceFeature : PersistenceFeatureBase
+public class EFCoreAlterationsPersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public EFCoreAlterationsPersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -32,6 +32,7 @@ public class EFCoreAlterationsPersistenceFeature : PersistenceFeatureBase();
AddEntityStore();
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs
index a31477233..c370c89d8 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.Identity.Entities;
@@ -13,12 +15,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Identity;
///
[DependsOn(typeof(IdentityFeature))]
[PublicAPI]
-public class EFCoreIdentityPersistenceFeature : PersistenceFeatureBase
+public class EFCoreIdentityPersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public EFCoreIdentityPersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -36,6 +36,8 @@ public class EFCoreIdentityPersistenceFeature : PersistenceFeatureBase();
AddEntityStore();
AddEntityStore();
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs
index 7dbe21ee1..462d55b3a 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Extensions;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
@@ -9,11 +11,10 @@ using Microsoft.Extensions.DependencyInjection;
namespace Elsa.EntityFrameworkCore.Modules.Labels;
[DependsOn(typeof(LabelsFeature))]
-public class EFCoreLabelPersistenceFeature : PersistenceFeatureBase
+public class EFCoreLabelPersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- public EFCoreLabelPersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
public override void Configure()
{
@@ -28,6 +29,8 @@ public class EFCoreLabelPersistenceFeature : PersistenceFeatureBase();
AddEntityStore();
}
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs
index 812525368..6c4a28c54 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.Workflows.Management.Entities;
@@ -11,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management;
/// Configures the feature with an Entity Framework Core persistence provider.
///
[DependsOn(typeof(WorkflowManagementFeature))]
-public class EFCoreWorkflowDefinitionPersistenceFeature : PersistenceFeatureBase
+public class EFCoreWorkflowDefinitionPersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public EFCoreWorkflowDefinitionPersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -32,6 +32,8 @@ public class EFCoreWorkflowDefinitionPersistenceFeature : PersistenceFeatureBase
{
base.Apply();
+ Services.AddScoped(DbExceptionHandler);
+
AddEntityStore();
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs
index d1188a726..aebdfc924 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.Workflows.Management.Entities;
@@ -11,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management;
/// Configures the feature with an Entity Framework Core persistence provider.
///
[DependsOn(typeof(WorkflowManagementFeature))]
-public class EFCoreWorkflowInstancePersistenceFeature : PersistenceFeatureBase
+public class EFCoreWorkflowInstancePersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public EFCoreWorkflowInstancePersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -29,6 +29,8 @@ public class EFCoreWorkflowInstancePersistenceFeature : PersistenceFeatureBase();
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs
index 3f702d065..f73185bb7 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.Workflows.Management.Entities;
@@ -15,12 +17,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management;
[DependsOn(typeof(WorkflowInstancesFeature))]
[DependsOn(typeof(WorkflowDefinitionsFeature))]
[PublicAPI]
-public class WorkflowManagementPersistenceFeature : PersistenceFeatureBase
+public class WorkflowManagementPersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public WorkflowManagementPersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -34,6 +34,8 @@ public class WorkflowManagementPersistenceFeature : PersistenceFeatureBase();
AddEntityStore();
}
diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
index 3cf255f7e..caf87fb14 100644
--- a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
+++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs
@@ -1,4 +1,6 @@
using Elsa.EntityFrameworkCore.Common;
+using Elsa.EntityFrameworkCore.Common.Contracts;
+using Elsa.EntityFrameworkCore.Handlers;
using Elsa.Features.Attributes;
using Elsa.Features.Services;
using Elsa.KeyValues.Entities;
@@ -13,12 +15,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Runtime;
/// Configures the default workflow runtime to use EF Core persistence providers.
///
[DependsOn(typeof(WorkflowRuntimeFeature))]
-public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase
+public class EFCoreWorkflowRuntimePersistenceFeature(IModule module) : PersistenceFeatureBase(module)
{
- ///
- public EFCoreWorkflowRuntimePersistenceFeature(IModule module) : base(module)
- {
- }
+ /// Delegate for determining the exception handler.
+ public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler();
///
public override void Configure()
@@ -42,6 +42,8 @@ public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase();
AddStore();
AddEntityStore();
diff --git a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
index be3520236..93765f25c 100644
--- a/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
+++ b/src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs
@@ -165,7 +165,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
Action? statusUpdatedCallback = null,
CancellationTokens cancellationTokens = default)
{
- // Setup a workflow execution context.
+ // Set up a workflow execution context.
var workflowExecutionContext = new WorkflowExecutionContext(
serviceProvider,
workflowGraph,
diff --git a/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs b/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs
new file mode 100644
index 000000000..2af7ab1e2
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs
@@ -0,0 +1,8 @@
+namespace Elsa.Workflows.Exceptions;
+
+/// An exception that occurs during data processing.
+public class DataProcessingException(bool isUkViolation, string message, Exception exception) : Exception(message, exception)
+{
+ /// Gets a value indicating whether the exception is a Unique Key violation.
+ public bool IsUkViolation { get; } = isUkViolation;
+}