From 1101bc2cb012b1ff6d867b0cc946285bb69dd18b Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 30 Jul 2023 16:20:43 +0330 Subject: [PATCH 01/18] Fix Error Endpoint Routing does not support UseMvc --- src/samples/WebApiSample/WebApiSample/Startup.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/samples/WebApiSample/WebApiSample/Startup.cs b/src/samples/WebApiSample/WebApiSample/Startup.cs index 13a19ddd8..0eee8a49e 100644 --- a/src/samples/WebApiSample/WebApiSample/Startup.cs +++ b/src/samples/WebApiSample/WebApiSample/Startup.cs @@ -44,11 +44,14 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseDeveloperExceptionPage(); } - + app.UseRouting(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1")); - app.UseMvc(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute("default", "{controller=Workflows}/{action=Get}"); + }); var host = app.ApplicationServices.GetService(); host.RegisterWorkflow(); From 04c116cbec3916ce30695b338d57fb4484909980 Mon Sep 17 00:00:00 2001 From: Dani Horon Date: Thu, 9 May 2024 15:00:16 +0300 Subject: [PATCH 02/18] fix: prevent redis provider from crashing when using deleteComplete --- .../Services/RedisPersistenceProvider.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/providers/WorkflowCore.Providers.Redis/Services/RedisPersistenceProvider.cs b/src/providers/WorkflowCore.Providers.Redis/Services/RedisPersistenceProvider.cs index 6bf8df875..eb76fa29e 100644 --- a/src/providers/WorkflowCore.Providers.Redis/Services/RedisPersistenceProvider.cs +++ b/src/providers/WorkflowCore.Providers.Redis/Services/RedisPersistenceProvider.cs @@ -92,6 +92,10 @@ public Task> GetWorkflowInstances(WorkflowStatus? public async Task GetWorkflowInstance(string Id, CancellationToken _ = default) { var raw = await _redis.HashGetAsync($"{_prefix}.{WORKFLOW_SET}", Id); + if (!raw.HasValue) + { + return null; + } return JsonConvert.DeserializeObject(raw, _serializerSettings); } From f72cc11b2e3ebc15ea3fbfbd4296d098ab8409cf Mon Sep 17 00:00:00 2001 From: "Xi Wang (AZURE)" Date: Fri, 24 May 2024 14:49:03 -0700 Subject: [PATCH 03/18] [Providers.Azure] Move away from deprecated libs and support TokenCredential --- .../Models/ControlledLock.cs | 7 +- .../ServiceCollectionExtensions.cs | 43 ++++++++++- .../Services/AzureLockManager.cs | 35 +++++---- .../Services/AzureStorageQueueProvider.cs | 41 ++++++----- .../Services/CosmosClientFactory.cs | 6 ++ .../Services/ServiceBusLifeCycleEventHub.cs | 73 +++++++++++-------- .../WorkflowCore.Providers.Azure.csproj | 8 +- 7 files changed, 142 insertions(+), 71 deletions(-) diff --git a/src/providers/WorkflowCore.Providers.Azure/Models/ControlledLock.cs b/src/providers/WorkflowCore.Providers.Azure/Models/ControlledLock.cs index 5b0343456..587378e15 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Models/ControlledLock.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Models/ControlledLock.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.WindowsAzure.Storage.Blob; +using Azure.Storage.Blobs.Specialized; namespace WorkflowCore.Providers.Azure.Models { @@ -7,9 +6,9 @@ class ControlledLock { public string Id { get; set; } public string LeaseId { get; set; } - public CloudBlockBlob Blob { get; set; } + public BlockBlobClient Blob { get; set; } - public ControlledLock(string id, string leaseId, CloudBlockBlob blob) + public ControlledLock(string id, string leaseId, BlockBlobClient blob) { Id = id; LeaseId = leaseId; diff --git a/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs b/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs index 0aa1963e4..6e3a92d5d 100644 --- a/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs +++ b/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using System; +using Azure.Core; +using Microsoft.Extensions.Logging; using WorkflowCore.Interface; using WorkflowCore.Models; using WorkflowCore.Providers.Azure.Interface; @@ -15,6 +17,13 @@ public static WorkflowOptions UseAzureSynchronization(this WorkflowOptions optio return options; } + public static WorkflowOptions UseAzureSynchronization(this WorkflowOptions options, Uri blobEndpoint, Uri queueEndpoint, TokenCredential tokenCredential) + { + options.UseQueueProvider(sp => new AzureStorageQueueProvider(queueEndpoint, tokenCredential, sp.GetService())); + options.UseDistributedLockManager(sp => new AzureLockManager(blobEndpoint, tokenCredential, sp.GetService())); + return options; + } + public static WorkflowOptions UseAzureServiceBusEventHub( this WorkflowOptions options, string connectionString, @@ -27,6 +36,19 @@ public static WorkflowOptions UseAzureServiceBusEventHub( return options; } + public static WorkflowOptions UseAzureServiceBusEventHub( + this WorkflowOptions options, + string fullyQualifiedNamespace, + TokenCredential tokenCredential, + string topicName, + string subscriptionName) + { + options.UseEventHub(sp => new ServiceBusLifeCycleEventHub( + fullyQualifiedNamespace, tokenCredential, topicName, subscriptionName, sp.GetService())); + + return options; + } + public static WorkflowOptions UseCosmosDbPersistence( this WorkflowOptions options, string connectionString, @@ -44,5 +66,24 @@ public static WorkflowOptions UseCosmosDbPersistence( options.UsePersistence(sp => new CosmosDbPersistenceProvider(sp.GetService(), databaseId, sp.GetService(), cosmosDbStorageOptions)); return options; } + + public static WorkflowOptions UseCosmosDbPersistence( + this WorkflowOptions options, + string accountEndpoint, + TokenCredential tokenCredential, + string databaseId, + CosmosDbStorageOptions cosmosDbStorageOptions = null) + { + if (cosmosDbStorageOptions == null) + { + cosmosDbStorageOptions = new CosmosDbStorageOptions(); + } + + options.Services.AddSingleton(sp => new CosmosClientFactory(accountEndpoint, tokenCredential)); + options.Services.AddTransient(sp => new CosmosDbProvisioner(sp.GetService(), cosmosDbStorageOptions)); + options.Services.AddSingleton(sp => new WorkflowPurger(sp.GetService(), databaseId, cosmosDbStorageOptions)); + options.UsePersistence(sp => new CosmosDbPersistenceProvider(sp.GetService(), databaseId, sp.GetService(), cosmosDbStorageOptions)); + return options; + } } } diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs b/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs index c52e823c7..d0134f790 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Azure.Core; +using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Specialized; using Microsoft.Extensions.Logging; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Blob; using WorkflowCore.Interface; using WorkflowCore.Providers.Azure.Models; @@ -13,11 +15,11 @@ namespace WorkflowCore.Providers.Azure.Services { public class AzureLockManager: IDistributedLockProvider { - private readonly CloudBlobClient _client; + private readonly BlobServiceClient _client; private readonly ILogger _logger; private readonly List _locks = new List(); private readonly AutoResetEvent _mutex = new AutoResetEvent(true); - private CloudBlobContainer _container; + private BlobContainerClient _container; private Timer _renewTimer; private TimeSpan LockTimeout => TimeSpan.FromMinutes(1); private TimeSpan RenewInterval => TimeSpan.FromSeconds(45); @@ -25,26 +27,31 @@ public class AzureLockManager: IDistributedLockProvider public AzureLockManager(string connectionString, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - var account = CloudStorageAccount.Parse(connectionString); - _client = account.CreateCloudBlobClient(); + _client = new BlobServiceClient(connectionString); + } + + public AzureLockManager(Uri blobEndpoint, TokenCredential tokenCredential, ILoggerFactory logFactory) + { + _logger = logFactory.CreateLogger(); + _client = new BlobServiceClient(blobEndpoint, tokenCredential); } public async Task AcquireLock(string Id, CancellationToken cancellationToken) { - var blob = _container.GetBlockBlobReference(Id); + var blob = _container.GetBlockBlobClient(Id); if (!await blob.ExistsAsync()) - await blob.UploadTextAsync(string.Empty); + await blob.UploadAsync(new MemoryStream()); if (_mutex.WaitOne()) { try { - var leaseId = await blob.AcquireLeaseAsync(LockTimeout); - _locks.Add(new ControlledLock(Id, leaseId, blob)); + var lease = await blob.GetBlobLeaseClient().AcquireAsync(LockTimeout); + _locks.Add(new ControlledLock(Id, lease.Value.LeaseId, blob)); return true; } - catch (StorageException ex) + catch (Exception ex) { _logger.LogDebug($"Failed to acquire lock {Id} - {ex.Message}"); return false; @@ -69,7 +76,7 @@ public async Task ReleaseLock(string Id) { try { - await entry.Blob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(entry.LeaseId)); + await entry.Blob.GetBlobLeaseClient(entry.LeaseId).ReleaseAsync(); } catch (Exception ex) { @@ -87,7 +94,7 @@ public async Task ReleaseLock(string Id) public async Task Start() { - _container = _client.GetContainerReference("workflowcore-locks"); + _container = _client.GetBlobContainerClient("workflowcore-locks"); await _container.CreateIfNotExistsAsync(); _renewTimer = new Timer(RenewLeases, null, RenewInterval, RenewInterval); } @@ -128,7 +135,7 @@ private async Task RenewLock(ControlledLock entry) { try { - await entry.Blob.RenewLeaseAsync(AccessCondition.GenerateLeaseCondition(entry.LeaseId)); + await entry.Blob.GetBlobLeaseClient(entry.LeaseId).ReleaseAsync(); } catch (Exception ex) { diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/AzureStorageQueueProvider.cs b/src/providers/WorkflowCore.Providers.Azure/Services/AzureStorageQueueProvider.cs index cbd76d1f7..3aea1d397 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/AzureStorageQueueProvider.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/AzureStorageQueueProvider.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Azure.Core; +using Azure.Storage.Queues; using Microsoft.Extensions.Logging; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Queue; using WorkflowCore.Interface; namespace WorkflowCore.Providers.Azure.Services @@ -13,41 +13,44 @@ public class AzureStorageQueueProvider : IQueueProvider { private readonly ILogger _logger; - private readonly Dictionary _queues = new Dictionary(); + private readonly Dictionary _queues = new Dictionary(); public bool IsDequeueBlocking => false; public AzureStorageQueueProvider(string connectionString, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - var account = CloudStorageAccount.Parse(connectionString); - var client = account.CreateCloudQueueClient(); + var client = new QueueServiceClient(connectionString); - _queues[QueueType.Workflow] = client.GetQueueReference("workflowcore-workflows"); - _queues[QueueType.Event] = client.GetQueueReference("workflowcore-events"); - _queues[QueueType.Index] = client.GetQueueReference("workflowcore-index"); + _queues[QueueType.Workflow] = client.GetQueueClient("workflowcore-workflows"); + _queues[QueueType.Event] = client.GetQueueClient("workflowcore-events"); + _queues[QueueType.Index] = client.GetQueueClient("workflowcore-index"); + } + + public AzureStorageQueueProvider(Uri queueEndpoint, TokenCredential tokenCredential, ILoggerFactory logFactory) + { + _logger = logFactory.CreateLogger(); + var client = new QueueServiceClient(queueEndpoint, tokenCredential); + + _queues[QueueType.Workflow] = client.GetQueueClient("workflowcore-workflows"); + _queues[QueueType.Event] = client.GetQueueClient("workflowcore-events"); + _queues[QueueType.Index] = client.GetQueueClient("workflowcore-index"); } public async Task QueueWork(string id, QueueType queue) { - var msg = new CloudQueueMessage(id); - await _queues[queue].AddMessageAsync(msg); + await _queues[queue].SendMessageAsync(id); } public async Task DequeueWork(QueueType queue, CancellationToken cancellationToken) { - CloudQueue cloudQueue = _queues[queue]; - - if (cloudQueue == null) - return null; - - var msg = await cloudQueue.GetMessageAsync(); + var msg = await _queues[queue].ReceiveMessageAsync(); - if (msg == null) + if (msg == null || msg.Value == null) return null; - await cloudQueue.DeleteMessageAsync(msg); - return msg.AsString; + await _queues[queue].DeleteMessageAsync(msg.Value.MessageId, msg.Value.PopReceipt); + return msg.Value.Body.ToString(); } public async Task Start() diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs b/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs index 9cb4cc572..12b9d9b96 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs @@ -1,4 +1,5 @@ using System; +using Azure.Core; using Microsoft.Azure.Cosmos; using WorkflowCore.Providers.Azure.Interface; @@ -15,6 +16,11 @@ public CosmosClientFactory(string connectionString) _client = new CosmosClient(connectionString); } + public CosmosClientFactory(string accountEndpoint, TokenCredential tokenCredential) + { + _client = new CosmosClient(accountEndpoint, tokenCredential); + } + public CosmosClient GetCosmosClient() { return this._client; diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/ServiceBusLifeCycleEventHub.cs b/src/providers/WorkflowCore.Providers.Azure/Services/ServiceBusLifeCycleEventHub.cs index 85f7a4245..f1ce10984 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/ServiceBusLifeCycleEventHub.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/ServiceBusLifeCycleEventHub.cs @@ -3,7 +3,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Azure.ServiceBus; +using Azure.Core; +using Azure.Messaging.ServiceBus; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using WorkflowCore.Interface; @@ -13,9 +14,11 @@ namespace WorkflowCore.Providers.Azure.Services { public class ServiceBusLifeCycleEventHub : ILifeCycleEventHub { - private readonly ITopicClient _topicClient; private readonly ILogger _logger; - private readonly ISubscriptionClient _subscriptionClient; + private readonly ServiceBusSender _sender; + private readonly ServiceBusReceiver _receiver; + private readonly ServiceBusProcessor _processor; + private readonly ICollection> _subscribers = new HashSet>(); private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings { @@ -29,20 +32,38 @@ public ServiceBusLifeCycleEventHub( string subscriptionName, ILoggerFactory logFactory) { - _subscriptionClient = new SubscriptionClient(connectionString, topicName, subscriptionName); - _topicClient = new TopicClient(connectionString, topicName); + var client = new ServiceBusClient(connectionString); + _sender = client.CreateSender(topicName); + _receiver = client.CreateReceiver(topicName, subscriptionName); + _processor = client.CreateProcessor(topicName, subscriptionName, new ServiceBusProcessorOptions + { + AutoCompleteMessages = false + }); _logger = logFactory.CreateLogger(GetType()); } - public async Task PublishNotification(LifeCycleEvent evt) + public ServiceBusLifeCycleEventHub( + string fullyQualifiedNamespace, + TokenCredential tokenCredential, + string topicName, + string subscriptionName, + ILoggerFactory logFactory) { - var payload = JsonConvert.SerializeObject(evt, _serializerSettings); - var message = new Message(Encoding.Default.GetBytes(payload)) + var client = new ServiceBusClient(fullyQualifiedNamespace, tokenCredential); + _sender = client.CreateSender(topicName); + _receiver = client.CreateReceiver(topicName, subscriptionName); + _processor = client.CreateProcessor(topicName, subscriptionName, new ServiceBusProcessorOptions { - Label = evt.Reference - }; + AutoCompleteMessages = false + }); + _logger = logFactory.CreateLogger(GetType()); + } - await _topicClient.SendAsync(message); + public async Task PublishNotification(LifeCycleEvent evt) + { + var payload = JsonConvert.SerializeObject(evt, _serializerSettings); + var message = new ServiceBusMessage(payload); + await _sender.SendMessageAsync(message); } public void Subscribe(Action action) @@ -50,45 +71,39 @@ public void Subscribe(Action action) _subscribers.Add(action); } - public Task Start() + public async Task Start() { - var messageHandlerOptions = new MessageHandlerOptions(ExceptionHandler) - { - AutoComplete = false - }; - - _subscriptionClient.RegisterMessageHandler(MessageHandler, messageHandlerOptions); - - return Task.CompletedTask; + _processor.ProcessErrorAsync += ExceptionHandler; + _processor.ProcessMessageAsync += MessageHandler; + await _processor.StartProcessingAsync(); } public async Task Stop() { - await _topicClient.CloseAsync(); - await _subscriptionClient.CloseAsync(); + await _sender.CloseAsync(); + await _receiver.CloseAsync(); + await _processor.CloseAsync(); } - private async Task MessageHandler(Message message, CancellationToken cancellationToken) + private async Task MessageHandler(ProcessMessageEventArgs args) { try { - var payload = Encoding.Default.GetString(message.Body); + var payload = args.Message.Body.ToString(); var evt = JsonConvert.DeserializeObject( payload, _serializerSettings); NotifySubscribers(evt); - await _subscriptionClient - .CompleteAsync(message.SystemProperties.LockToken) - .ConfigureAwait(false); + await _receiver.CompleteMessageAsync(args.Message); } catch { - await _subscriptionClient.AbandonAsync(message.SystemProperties.LockToken); + await _receiver.AbandonMessageAsync(args.Message); } } - private Task ExceptionHandler(ExceptionReceivedEventArgs arg) + private Task ExceptionHandler(ProcessErrorEventArgs arg) { _logger.LogWarning(default, arg.Exception, "Error on receiving events"); diff --git a/src/providers/WorkflowCore.Providers.Azure/WorkflowCore.Providers.Azure.csproj b/src/providers/WorkflowCore.Providers.Azure/WorkflowCore.Providers.Azure.csproj index cedd72024..65517764c 100644 --- a/src/providers/WorkflowCore.Providers.Azure/WorkflowCore.Providers.Azure.csproj +++ b/src/providers/WorkflowCore.Providers.Azure/WorkflowCore.Providers.Azure.csproj @@ -16,10 +16,10 @@ - - - - + + + + From 2a0b27b5bf2d8b1b3b1813940f2d7a34135d45d8 Mon Sep 17 00:00:00 2001 From: "Xi Wang (AZURE)" Date: Thu, 30 May 2024 08:18:56 -0700 Subject: [PATCH 04/18] Fix typo --- .../WorkflowCore.Providers.Azure/Services/AzureLockManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs b/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs index d0134f790..6780a77ad 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/AzureLockManager.cs @@ -135,7 +135,7 @@ private async Task RenewLock(ControlledLock entry) { try { - await entry.Blob.GetBlobLeaseClient(entry.LeaseId).ReleaseAsync(); + await entry.Blob.GetBlobLeaseClient(entry.LeaseId).RenewAsync(); } catch (Exception ex) { From da17e9ee7ea13b99142eb2e0c867e27492e9c2ef Mon Sep 17 00:00:00 2001 From: Roland Schmitt Date: Wed, 14 Aug 2024 18:08:44 +0200 Subject: [PATCH 05/18] Fixed usage of CreateIndexes for mongo to avoid database connection already opening during ioc --- .../Services/MongoPersistenceProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs b/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs index fdab92cf6..d38ded2a5 100644 --- a/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs +++ b/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs @@ -23,7 +23,6 @@ public class MongoPersistenceProvider : IPersistenceProvider public MongoPersistenceProvider(IMongoDatabase database) { _database = database; - CreateIndexes(this); } static MongoPersistenceProvider() @@ -263,7 +262,7 @@ public async Task ClearSubscriptionToken(string eventSubscriptionId, string toke public void EnsureStoreExists() { - + CreateIndexes(this); } public async Task> GetSubscriptions(string eventName, string eventKey, DateTime asOf, CancellationToken cancellationToken = default) From 0b51d8ef84375354864da4d18a5b8c62ce2b7272 Mon Sep 17 00:00:00 2001 From: Roland Schmitt Date: Wed, 14 Aug 2024 18:35:44 +0200 Subject: [PATCH 06/18] Fixed mongo tests to call EnsureStoreExists --- .../MongoPersistenceProviderFixture.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/WorkflowCore.Tests.MongoDB/MongoPersistenceProviderFixture.cs b/test/WorkflowCore.Tests.MongoDB/MongoPersistenceProviderFixture.cs index c61b4b5e2..fd6546aca 100644 --- a/test/WorkflowCore.Tests.MongoDB/MongoPersistenceProviderFixture.cs +++ b/test/WorkflowCore.Tests.MongoDB/MongoPersistenceProviderFixture.cs @@ -1,5 +1,4 @@ using MongoDB.Driver; -using System; using WorkflowCore.Interface; using WorkflowCore.Persistence.MongoDB.Services; using WorkflowCore.UnitTests; @@ -23,7 +22,9 @@ protected override IPersistenceProvider Subject { var client = new MongoClient(MongoDockerSetup.ConnectionString); var db = client.GetDatabase(nameof(MongoPersistenceProviderFixture)); - return new MongoPersistenceProvider(db); + var provider = new MongoPersistenceProvider(db); + provider.EnsureStoreExists(); + return provider; } } } From 0f91b37284ad5456e71af7ee709b34a45132c6d4 Mon Sep 17 00:00:00 2001 From: dsbegnoche Date: Wed, 23 Oct 2024 14:16:55 -0500 Subject: [PATCH 07/18] upgrade to mongo 2.30 --- .../WorkflowCore.Persistence.MongoDB.csproj | 2 +- .../WorkflowCore.Tests.MongoDB.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj b/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj index e55685a2e..66cde70ce 100644 --- a/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj +++ b/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj @@ -22,7 +22,7 @@ - + diff --git a/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj b/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj index d30af9bec..77638e86b 100644 --- a/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj +++ b/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj @@ -22,7 +22,7 @@ - + From db61af319b04acdec151dbde3b2b797821ad9767 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Fri, 25 Oct 2024 08:32:24 -0700 Subject: [PATCH 08/18] Create CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..a7923835b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @danielgerlag @glucaci From ef17734ecc6995e8005738e1a8c4596deaa14b4f Mon Sep 17 00:00:00 2001 From: Ankur Charan Date: Mon, 30 Dec 2024 13:26:55 +0000 Subject: [PATCH 09/18] add cosmos mi --- .../ServiceCollectionExtensions.cs | 19 +++++++++++++++++++ .../Services/CosmosClientFactory.cs | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs b/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs index d6aec277d..aa3d5f106 100644 --- a/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs +++ b/src/providers/WorkflowCore.Providers.Azure/ServiceCollectionExtensions.cs @@ -46,5 +46,24 @@ public static WorkflowOptions UseCosmosDbPersistence( options.UsePersistence(sp => new CosmosDbPersistenceProvider(sp.GetService(), databaseId, sp.GetService(), cosmosDbStorageOptions)); return options; } + + public static WorkflowOptions UseCosmosDbPersistence( + this WorkflowOptions options, + CosmosClient client, + string databaseId, + CosmosDbStorageOptions cosmosDbStorageOptions = null, + CosmosClientOptions clientOptions = null) + { + if (cosmosDbStorageOptions == null) + { + cosmosDbStorageOptions = new CosmosDbStorageOptions(); + } + + options.Services.AddSingleton(sp => new CosmosClientFactory(client)); + options.Services.AddTransient(sp => new CosmosDbProvisioner(sp.GetService(), cosmosDbStorageOptions)); + options.Services.AddSingleton(sp => new WorkflowPurger(sp.GetService(), databaseId, cosmosDbStorageOptions)); + options.UsePersistence(sp => new CosmosDbPersistenceProvider(sp.GetService(), databaseId, sp.GetService(), cosmosDbStorageOptions)); + return options; + } } } diff --git a/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs b/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs index ac5dc7f4a..2128d45e0 100644 --- a/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs +++ b/src/providers/WorkflowCore.Providers.Azure/Services/CosmosClientFactory.cs @@ -15,6 +15,11 @@ public CosmosClientFactory(string connectionString, CosmosClientOptions clientOp _client = new CosmosClient(connectionString, clientOptions); } + public CosmosClientFactory(CosmosClient client) + { + _client = client; + } + public CosmosClient GetCosmosClient() { return this._client; From 636ca0a03fb33ef6d1656558ddec5baaa7d6d476 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Wed, 1 Jan 2025 19:08:29 -0800 Subject: [PATCH 10/18] Update Directory.Build.props --- src/Directory.Build.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index cb377a989..d7f79daf7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,10 +4,10 @@ https://github.com/danielgerlag/workflow-core/blob/master/LICENSE.md git https://github.com/danielgerlag/workflow-core.git - 3.10.0 - 3.11.0.0 - 3.11.0.0 + 3.12.0 + 3.12.0.0 + 3.12.0.0 https://github.com/danielgerlag/workflow-core/raw/master/src/logo.png - 3.11.0 + 3.12.0 From fc7989085e0e9d77259fecf49ff7eee497ede408 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Thu, 2 Jan 2025 18:31:21 -0800 Subject: [PATCH 11/18] Update Directory.Build.props --- src/Directory.Build.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d7f79daf7..63b3fef6f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,10 +4,10 @@ https://github.com/danielgerlag/workflow-core/blob/master/LICENSE.md git https://github.com/danielgerlag/workflow-core.git - 3.12.0 - 3.12.0.0 - 3.12.0.0 + 3.13.0 + 3.13.0.0 + 3.13.0.0 https://github.com/danielgerlag/workflow-core/raw/master/src/logo.png - 3.12.0 + 3.13.0 From 8f652f07849ec19b26ff6a366c00e371483f9529 Mon Sep 17 00:00:00 2001 From: Jordan Wallwork Date: Fri, 3 Jan 2025 14:22:10 +0000 Subject: [PATCH 12/18] Upgrade Persistence.SqlServer to use net9 --- .github/workflows/dotnet.yml | 1 + .../WorkflowCore.Persistence.SqlServer.csproj | 13 ++++++++++++- test/Directory.Build.props | 2 +- .../WorkflowCore.Tests.SqlServer.csproj | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index b0c3ab704..b311e62d1 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -120,6 +120,7 @@ jobs: 3.1.x 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build diff --git a/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj b/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj index cfef6609f..2c4f5cee3 100644 --- a/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj +++ b/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj @@ -4,7 +4,7 @@ Workflow Core SQL Server Persistence Provider 1.8.0 Daniel Gerlag - netstandard2.1;net6.0;net8.0 + netstandard2.1;net6.0;net8.0;net9.0 WorkflowCore.Persistence.SqlServer WorkflowCore.Persistence.SqlServer workflow;.NET;Core;state machine;WorkflowCore @@ -45,6 +45,17 @@ + + + + All + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 2dc7c95f9..0a98ed47a 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -18,7 +18,7 @@ - + \ No newline at end of file diff --git a/test/WorkflowCore.Tests.SqlServer/WorkflowCore.Tests.SqlServer.csproj b/test/WorkflowCore.Tests.SqlServer/WorkflowCore.Tests.SqlServer.csproj index bf9557556..11b6c00e2 100644 --- a/test/WorkflowCore.Tests.SqlServer/WorkflowCore.Tests.SqlServer.csproj +++ b/test/WorkflowCore.Tests.SqlServer/WorkflowCore.Tests.SqlServer.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0 + net6.0;net8.0;net9.0 From 1397060a078f9a228cb02a78882bc0091eced3f8 Mon Sep 17 00:00:00 2001 From: Jordan Wallwork Date: Wed, 15 Jan 2025 16:31:44 +0000 Subject: [PATCH 13/18] Use later versions of actions to support .net9 --- .github/workflows/dotnet.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index b311e62d1..1a6532ae7 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -112,9 +112,9 @@ jobs: SQLServer-Tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 3.1.x From 09cd773cdc22c161221e50928e813752fddadfa7 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Sat, 18 Jan 2025 07:58:27 -0800 Subject: [PATCH 14/18] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 53ef98486..1eeb0fa66 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Workflow Core [![Build status](https://ci.appveyor.com/api/projects/status/xnby6p5v4ur04u76?svg=true)](https://ci.appveyor.com/project/danielgerlag/workflow-core) +[](https://api.gitsponsors.com/api/badge/link?p=xj6mObb7nZAJGyuABfd8nD5XWf3SE4oUfw0vmCgSiJeIfNlzJAej0FWX8oFdYm6D7bvZpCf6qANVBNPWid4dRQ==) Workflow Core is a light weight embeddable workflow engine targeting .NET Standard. Think: long running processes with multiple tasks that need to track state. It supports pluggable persistence and concurrency providers to allow for multi-node clusters. From 4a260b096b0273bd322d33c083487740fd900fc1 Mon Sep 17 00:00:00 2001 From: Florian Rohrer Date: Thu, 12 Jun 2025 17:39:27 +0200 Subject: [PATCH 15/18] Upgrade MongoDB driver to 3.4.0 --- .../Services/MongoPersistenceProvider.cs | 2 +- .../WorkflowCore.Persistence.MongoDB.csproj | 4 ++-- test/Directory.Build.props | 13 +++---------- test/WorkflowCore.Tests.MongoDB/MongoDockerSetup.cs | 9 +++++++-- .../WorkflowCore.Tests.MongoDB.csproj | 6 +++--- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs b/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs index d38ded2a5..a72340d68 100644 --- a/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs +++ b/src/providers/WorkflowCore.Persistence.MongoDB/Services/MongoPersistenceProvider.cs @@ -197,7 +197,7 @@ public async Task> GetWorkflowInstances(IEnumerabl public async Task> GetWorkflowInstances(WorkflowStatus? status, string type, DateTime? createdFrom, DateTime? createdTo, int skip, int take) { - IMongoQueryable result = WorkflowInstances.AsQueryable(); + IQueryable result = WorkflowInstances.AsQueryable(); if (status.HasValue) result = result.Where(x => x.Status == status.Value); diff --git a/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj b/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj index 66cde70ce..5dfdf800f 100644 --- a/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj +++ b/src/providers/WorkflowCore.Persistence.MongoDB/WorkflowCore.Persistence.MongoDB.csproj @@ -3,7 +3,7 @@ Workflow Core MongoDB Persistence Provider Daniel Gerlag - netstandard2.0 + netstandard2.1 WorkflowCore.Persistence.MongoDB WorkflowCore.Persistence.MongoDB workflow;.NET;Core;state machine;WorkflowCore;MongoDB;Mongo @@ -22,7 +22,7 @@ - + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 0a98ed47a..cdb7e1676 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -6,19 +6,12 @@ - - - + + + - - - - - - - \ No newline at end of file diff --git a/test/WorkflowCore.Tests.MongoDB/MongoDockerSetup.cs b/test/WorkflowCore.Tests.MongoDB/MongoDockerSetup.cs index df281ce29..e5c18b341 100644 --- a/test/WorkflowCore.Tests.MongoDB/MongoDockerSetup.cs +++ b/test/WorkflowCore.Tests.MongoDB/MongoDockerSetup.cs @@ -1,25 +1,30 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; using Squadron; +using WorkflowCore.UnitTests; using Xunit; namespace WorkflowCore.Tests.MongoDB { public class MongoDockerSetup : IAsyncLifetime { - private readonly MongoResource _mongoResource; + private readonly MongoReplicaSetResource _mongoResource; public static string ConnectionString { get; set; } public MongoDockerSetup() { - _mongoResource = new MongoResource(); + _mongoResource = new MongoReplicaSetResource(); } public async Task InitializeAsync() { await _mongoResource.InitializeAsync(); ConnectionString = _mongoResource.ConnectionString; + BsonSerializer.TryRegisterSerializer(new ObjectSerializer(type => + ObjectSerializer.DefaultAllowedTypes(type) || type.FullName.StartsWith("WorkflowCore."))); } public Task DisposeAsync() diff --git a/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj b/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj index 77638e86b..0bffc02e8 100644 --- a/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj +++ b/test/WorkflowCore.Tests.MongoDB/WorkflowCore.Tests.MongoDB.csproj @@ -7,7 +7,7 @@ false false false - net6.0 + net8.0 @@ -21,8 +21,8 @@ - - + + From 5c683ff7c8ab1e0702c4e6aad0d4ace0376d0ea3 Mon Sep 17 00:00:00 2001 From: Florian Rohrer Date: Mon, 16 Jun 2025 11:07:58 +0200 Subject: [PATCH 16/18] Update .NET version in workflow to include 9.0.x, drop 3.1 --- .github/workflows/dotnet.yml | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 1a6532ae7..a3b389069 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -15,9 +15,9 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: | - 3.1.x 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -31,10 +31,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -48,10 +48,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -65,10 +65,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -82,10 +82,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -99,10 +99,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build @@ -114,10 +114,9 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x 9.0.x @@ -134,10 +133,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 3.1.x + dotnet-version: | 6.0.x 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build From b5802797070acb93ac1c213d3120f35976787662 Mon Sep 17 00:00:00 2001 From: Florian Rohrer Date: Mon, 16 Jun 2025 11:12:04 +0200 Subject: [PATCH 17/18] fix typo in documentation --- src/providers/WorkflowCore.Persistence.MongoDB/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/WorkflowCore.Persistence.MongoDB/README.md b/src/providers/WorkflowCore.Persistence.MongoDB/README.md index 911d8a9e4..9668e393d 100644 --- a/src/providers/WorkflowCore.Persistence.MongoDB/README.md +++ b/src/providers/WorkflowCore.Persistence.MongoDB/README.md @@ -24,7 +24,7 @@ By default (to maintain backwards compatibility), the state object is serialized This approach has some limitations, for example you cannot control which types will be used in MongoDB for particular fields and you cannot use basic types that are not present in JSON (decimal, timestamp, etc). To eliminate these limitations, you can use a direct object -> BSON serialization and utilize all serialization possibilities that MongoDb driver provides. You can read more in the [MongoDb CSharp documentation](https://mongodb.github.io/mongo-csharp-driver/1.11/serialization/). -To enable direct serilization you need to register a class map for you state class somewhere in your startup process before you run `WorkflowHost`. +To enable direct serialization you need to register a class map for you state class somewhere in your startup process before you run `WorkflowHost`. ```C# private void RunWorkflow() From a37e3e3379ace5c1afffc39902e8422c5c8abab6 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Thu, 19 Jun 2025 09:36:42 -0700 Subject: [PATCH 18/18] Update Directory.Build.props --- src/Directory.Build.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 63b3fef6f..061235f4f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,10 +4,10 @@ https://github.com/danielgerlag/workflow-core/blob/master/LICENSE.md git https://github.com/danielgerlag/workflow-core.git - 3.13.0 - 3.13.0.0 - 3.13.0.0 + 3.14.0 + 3.14.0.0 + 3.14.0.0 https://github.com/danielgerlag/workflow-core/raw/master/src/logo.png - 3.13.0 + 3.14.0