From 3c9ed131413747a49e16b012e95a8124e4e07f4c Mon Sep 17 00:00:00 2001 From: stidsborg Date: Sat, 30 May 2026 12:10:03 +0200 Subject: [PATCH 1/2] Updated Cleipnir.ResilientFunctions to the latest commit --- Cleipnir.ResilientFunctions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cleipnir.ResilientFunctions b/Cleipnir.ResilientFunctions index eb6bfc7..e5ec420 160000 --- a/Cleipnir.ResilientFunctions +++ b/Cleipnir.ResilientFunctions @@ -1 +1 @@ -Subproject commit eb6bfc7cced620537ff08295df38341e9b5ec87d +Subproject commit e5ec420fc1de4059050cf5c9587feae23237f147 From 6c75cb01f796b8cd00da50c9cff3ed30d73ebe5b Mon Sep 17 00:00:00 2001 From: stidsborg Date: Sat, 30 May 2026 12:17:53 +0200 Subject: [PATCH 2/2] Adapt to ResilientFunctions Settings/EffectId API changes The Settings constructor dropped leaseLength and added replicaHeartbeatFrequency, and EffectId no longer converts implicitly from int. - Options: replace LeaseLength with ReplicaHeartbeatFrequency and pass Settings args by name; also stop dropping UtcNow in Merge - FlowsContainer: rebuild Options by name so no options are dropped - Tests: construct InitialEffect with EffectId via 0.ToEffectId() - Samples: use replicaHeartbeatFrequency instead of leaseLength Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Flows/FunctionRegistrationTests.cs | 2 +- Cleipnir.Tests/Flows/ParamlessFlowsTests.cs | 2 +- Cleipnir.Tests/Flows/UnitFlowsTests.cs | 2 +- Cleipnir/FlowsContainer.cs | 21 +++++----- Cleipnir/Options.cs | 39 ++++++++++--------- Samples/Cleipnir.Sample.AspNet/Program.cs | 2 +- .../Program.cs | 2 +- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/Cleipnir.Tests/Flows/FunctionRegistrationTests.cs b/Cleipnir.Tests/Flows/FunctionRegistrationTests.cs index b136672..04c2336 100644 --- a/Cleipnir.Tests/Flows/FunctionRegistrationTests.cs +++ b/Cleipnir.Tests/Flows/FunctionRegistrationTests.cs @@ -35,7 +35,7 @@ await flows.Run( param: "SomeParam", new InitialState( [new MessageAndIdempotencyKey(new StringMessage("InitialMessageValue"))], - [new InitialEffect(0, "InitialEffectValue")] + [new InitialEffect(0.ToEffectId(), "InitialEffectValue")] ) ); diff --git a/Cleipnir.Tests/Flows/ParamlessFlowsTests.cs b/Cleipnir.Tests/Flows/ParamlessFlowsTests.cs index 65933e8..fee11a4 100644 --- a/Cleipnir.Tests/Flows/ParamlessFlowsTests.cs +++ b/Cleipnir.Tests/Flows/ParamlessFlowsTests.cs @@ -158,7 +158,7 @@ await flows.Run( "SomeInstanceId", new InitialState( [new MessageAndIdempotencyKey(new StringMessage("InitialMessageValue"))], - [new InitialEffect(0, "InitialEffectValue")] + [new InitialEffect(0.ToEffectId(), "InitialEffectValue")] ) ); diff --git a/Cleipnir.Tests/Flows/UnitFlowsTests.cs b/Cleipnir.Tests/Flows/UnitFlowsTests.cs index 2bb7195..d38a7d8 100644 --- a/Cleipnir.Tests/Flows/UnitFlowsTests.cs +++ b/Cleipnir.Tests/Flows/UnitFlowsTests.cs @@ -265,7 +265,7 @@ await flows.Run( param: "SomeParam", new InitialState( [new MessageAndIdempotencyKey(new StringMessage("InitialMessageValue"))], - [new InitialEffect(0, "InitialEffectValue")] + [new InitialEffect(0.ToEffectId(), "InitialEffectValue")] ) ); diff --git a/Cleipnir/FlowsContainer.cs b/Cleipnir/FlowsContainer.cs index b9c9502..6c6b41e 100644 --- a/Cleipnir/FlowsContainer.cs +++ b/Cleipnir/FlowsContainer.cs @@ -27,16 +27,17 @@ public FlowsContainer(IFunctionStore flowStore, IServiceProvider serviceProvider var logger = serviceProvider.GetRequiredService(); options = new Options( unhandledExceptionHandler: ex => logger.LogError(ex, "Unhandled exception in Cleipnir"), - options.RetentionPeriod, - options.RetentionCleanUpFrequency, - options.LeaseLength, - options.EnableWatchdogs, - options.WatchdogCheckFrequency, - options.MessagesPullFrequency, - options.MessagesDefaultMaxWaitForCompletion, - options.DelayStartup, - options.MaxParallelRetryInvocations, - options.Serializer + retentionPeriod: options.RetentionPeriod, + retentionCleanUpFrequency: options.RetentionCleanUpFrequency, + enableWatchdogs: options.EnableWatchdogs, + watchdogCheckFrequency: options.WatchdogCheckFrequency, + messagesPullFrequency: options.MessagesPullFrequency, + messagesDefaultMaxWaitForCompletion: options.MessagesDefaultMaxWaitForCompletion, + delayStartup: options.DelayStartup, + maxParallelRetryInvocations: options.MaxParallelRetryInvocations, + serializer: options.Serializer, + utcNow: options.UtcNow, + replicaHeartbeatFrequency: options.ReplicaHeartbeatFrequency ); } diff --git a/Cleipnir/Options.cs b/Cleipnir/Options.cs index 48ccff8..2d3807f 100644 --- a/Cleipnir/Options.cs +++ b/Cleipnir/Options.cs @@ -13,7 +13,6 @@ public class Options internal Action? UnhandledExceptionHandler { get; } internal TimeSpan? RetentionPeriod { get; } internal TimeSpan? RetentionCleanUpFrequency { get; } - internal TimeSpan? LeaseLength { get; } internal bool? EnableWatchdogs { get; } internal TimeSpan? WatchdogCheckFrequency { get; } internal TimeSpan? DelayStartup { get; } @@ -22,6 +21,7 @@ public class Options internal TimeSpan? MessagesDefaultMaxWaitForCompletion { get; } internal ISerializer? Serializer { get; } internal UtcNow? UtcNow { get; } + internal TimeSpan? ReplicaHeartbeatFrequency { get; } /// /// Configuration options for Cleipnir @@ -29,7 +29,6 @@ public class Options /// Callback handler for unhandled flow exceptions /// Period to keep completed flows before deletion. Default infinite. /// Retention clean-up check frequency. Default 1 hour when retention period is not infinite. - /// Flow lease-length. Leases are automatically renewed. Default 60 seconds. /// Enable background crashed, interrupted and postponed flow scheduling. Default true. /// Check frequency for eligible crashed, interrupted and postponed flows. Default 1 second. /// Pull frequency for active/max-waiting messages. Default: 250ms @@ -38,11 +37,11 @@ public class Options /// Limit the number of watchdog started invocations. Default: 100. /// Specify custom serializer. Default built-in json-serializer. /// Provide custom delegate for providing current utc datetime. Default: () => DateTime.UtcNow + /// Heartbeat frequency for replica liveness detection. Default 1 second. public Options( Action? unhandledExceptionHandler = null, TimeSpan? retentionPeriod = null, TimeSpan? retentionCleanUpFrequency = null, - TimeSpan? leaseLength = null, bool? enableWatchdogs = null, TimeSpan? watchdogCheckFrequency = null, TimeSpan? messagesPullFrequency = null, @@ -50,12 +49,12 @@ public Options( TimeSpan? delayStartup = null, int? maxParallelRetryInvocations = null, ISerializer? serializer = null, - UtcNow? utcNow = null + UtcNow? utcNow = null, + TimeSpan? replicaHeartbeatFrequency = null ) { UnhandledExceptionHandler = unhandledExceptionHandler; WatchdogCheckFrequency = watchdogCheckFrequency; - LeaseLength = leaseLength; RetentionPeriod = retentionPeriod; RetentionCleanUpFrequency = retentionCleanUpFrequency; EnableWatchdogs = enableWatchdogs; @@ -65,6 +64,7 @@ public Options( MaxParallelRetryInvocations = maxParallelRetryInvocations; Serializer = serializer; UtcNow = utcNow; + ReplicaHeartbeatFrequency = replicaHeartbeatFrequency; } public Options Merge(Options options) @@ -73,30 +73,31 @@ public Options Merge(Options options) UnhandledExceptionHandler ?? options.UnhandledExceptionHandler, RetentionPeriod ?? options.RetentionPeriod, RetentionCleanUpFrequency ?? options.RetentionCleanUpFrequency, - LeaseLength ?? options.LeaseLength, EnableWatchdogs ?? options.EnableWatchdogs, WatchdogCheckFrequency ?? options.WatchdogCheckFrequency, MessagesPullFrequency ?? options.MessagesPullFrequency, MessagesDefaultMaxWaitForCompletion ?? options.MessagesDefaultMaxWaitForCompletion, DelayStartup ?? options.DelayStartup, MaxParallelRetryInvocations ?? options.MaxParallelRetryInvocations, - Serializer ?? options.Serializer + Serializer ?? options.Serializer, + UtcNow ?? options.UtcNow, + ReplicaHeartbeatFrequency ?? options.ReplicaHeartbeatFrequency ); } internal Settings MapToSettings() => new( - UnhandledExceptionHandler, - RetentionPeriod, - RetentionCleanUpFrequency, - LeaseLength, - EnableWatchdogs, - WatchdogCheckFrequency, - MessagesPullFrequency, - MessagesDefaultMaxWaitForCompletion, - DelayStartup, - MaxParallelRetryInvocations, - Serializer, - UtcNow + unhandledExceptionHandler: UnhandledExceptionHandler, + retentionPeriod: RetentionPeriod, + retentionCleanUpFrequency: RetentionCleanUpFrequency, + enableWatchdogs: EnableWatchdogs, + watchdogCheckFrequency: WatchdogCheckFrequency, + messagesPullFrequency: MessagesPullFrequency, + messagesDefaultMaxWaitForCompletion: MessagesDefaultMaxWaitForCompletion, + delayStartup: DelayStartup, + maxParallelRetryInvocations: MaxParallelRetryInvocations, + serializer: Serializer, + utcNow: UtcNow, + replicaHeartbeatFrequency: ReplicaHeartbeatFrequency ); } diff --git a/Samples/Cleipnir.Sample.AspNet/Program.cs b/Samples/Cleipnir.Sample.AspNet/Program.cs index b369ccf..63cdee5 100644 --- a/Samples/Cleipnir.Sample.AspNet/Program.cs +++ b/Samples/Cleipnir.Sample.AspNet/Program.cs @@ -27,7 +27,7 @@ private static async Task Main(string[] args) await DatabaseHelper.CreateDatabaseIfNotExists(connectionString); //use to create db initially or clean existing state in database builder.Services.AddFlows(c => c .UsePostgresStore(connectionString) - .WithOptions(new Options(leaseLength: TimeSpan.FromSeconds(5))) + .WithOptions(new Options(replicaHeartbeatFrequency: TimeSpan.FromSeconds(5))) .RegisterFlow() ); diff --git a/Samples/Cleipnir.Sample.Presentation.AspNet/Program.cs b/Samples/Cleipnir.Sample.Presentation.AspNet/Program.cs index a51d195..b0339cf 100644 --- a/Samples/Cleipnir.Sample.Presentation.AspNet/Program.cs +++ b/Samples/Cleipnir.Sample.Presentation.AspNet/Program.cs @@ -32,7 +32,7 @@ private static async Task Main(string[] args) //await DatabaseHelper.RecreateDatabase(connectionString); builder.Services.AddFlows(c => c .UsePostgresStore(connectionString) - .WithOptions(new Options(leaseLength: TimeSpan.FromSeconds(5), messagesDefaultMaxWaitForCompletion: TimeSpan.MaxValue)) + .WithOptions(new Options(replicaHeartbeatFrequency: TimeSpan.FromSeconds(5), messagesDefaultMaxWaitForCompletion: TimeSpan.MaxValue)) .RegisterFlow() .RegisterFlow>() .RegisterFlow()