Skip to content

Commit

Permalink
feat: add sample project to evaluate cooperative sticky strategy support
Browse files Browse the repository at this point in the history
test: add unit tests and fix bug in ClusterConfiguration

- Added 3 new test files to improve coverage:
  - ConsumerConfigurationBuilderTests.cs
  - KafkaConfigTests.cs
  - PartitionAssignmentStrategyTests.cs
- Fixed a bug in ClusterConfiguration related to AutoCommitInterval initialization

chore: update AutoCommitInterval to 100ms in Cooperative-sticky sample

- Updated AutoCommitInterval in Cooperative-sticky sample Program.cs to 100ms.

fix: resolve Codacy issues

- Fixed various code quality issues flagged by Codacy.
  • Loading branch information
golanbz authored and brmagadutra committed Feb 13, 2025
1 parent b925601 commit 83bce82
Show file tree
Hide file tree
Showing 11 changed files with 462 additions and 3 deletions.
7 changes: 7 additions & 0 deletions KafkaFlow.sln
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KafkaFlow.Sample.OpenTelemetry", "samples\KafkaFlow.Sample.OpenTelemetry\KafkaFlow.Sample.OpenTelemetry.csproj", "{E9E8B374-4165-45F2-8DF5-F141E141AC1D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KafkaFlow.Sample.CooperativeSticky", "samples\KafkaFlow.Sample.CooperativeSticky\KafkaFlow.Sample.CooperativeSticky.csproj", "{DBF7B091-11AE-402F-9F36-7E7EB3901B0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -222,6 +224,10 @@ Global
{E9E8B374-4165-45F2-8DF5-F141E141AC1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9E8B374-4165-45F2-8DF5-F141E141AC1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9E8B374-4165-45F2-8DF5-F141E141AC1D}.Release|Any CPU.Build.0 = Release|Any CPU
{DBF7B091-11AE-402F-9F36-7E7EB3901B0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBF7B091-11AE-402F-9F36-7E7EB3901B0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBF7B091-11AE-402F-9F36-7E7EB3901B0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBF7B091-11AE-402F-9F36-7E7EB3901B0B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -265,6 +271,7 @@ Global
{1755E8DB-970C-4A24-8B7C-A2BEC1410BEE} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068}
{80080C1D-579E-4AB2-935D-5CFFC51843D8} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068}
{E9E8B374-4165-45F2-8DF5-F141E141AC1D} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B}
{DBF7B091-11AE-402F-9F36-7E7EB3901B0B} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6AE955B5-16B0-41CF-9F12-66D15B3DD1AB}
Expand Down
44 changes: 44 additions & 0 deletions samples/KafkaFlow.Sample.CooperativeSticky/HostedService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using KafkaFlow.Producers;
using Microsoft.Extensions.Hosting;

namespace KafkaFlow.Sample.CooperativeSticky;

public class HostedService : IHostedService
{
private IMessageProducer _producer;
const string producerName = "PrintConsole";
const string topicName = "sample-topic";


public HostedService(IProducerAccessor producerAccessor)
{
_producer = producerAccessor.GetProducer(producerName);
}

public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
while (true)
{
await _producer.ProduceAsync(
topicName,
Guid.NewGuid().ToString(),
new TestMessage { Text = $"Message: {Guid.NewGuid()}" });
await Task.Delay(500, cancellationToken);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<NoWarn>1701;1702;CS1591;SA1600</NoWarn>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<NoWarn>1701;1702;CS1591;SA1600</NoWarn>
</PropertyGroup>


<ItemGroup>
<ProjectReference Include="..\..\src\KafkaFlow.LogHandler.Console\KafkaFlow.LogHandler.Console.csproj" />
<ProjectReference Include="..\..\src\KafkaFlow.Microsoft.DependencyInjection\KafkaFlow.Microsoft.DependencyInjection.csproj" />
<ProjectReference Include="..\..\src\KafkaFlow.Serializer.ProtobufNet\KafkaFlow.Serializer.ProtobufNet.csproj" />
<ProjectReference Include="..\..\src\KafkaFlow\KafkaFlow.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
</ItemGroup>


</Project>
18 changes: 18 additions & 0 deletions samples/KafkaFlow.Sample.CooperativeSticky/PrintConsoleHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;

namespace KafkaFlow.Sample.CooperativeSticky;

public class PrintConsoleHandler : IMessageHandler<TestMessage>
{
public Task Handle(IMessageContext context, TestMessage message)
{
Console.WriteLine(
"Partition: {0} | Offset: {1} | Message: {2}",
context.ConsumerContext.Partition,
context.ConsumerContext.Offset,
message.Text);

return Task.CompletedTask;
}
}
51 changes: 51 additions & 0 deletions samples/KafkaFlow.Sample.CooperativeSticky/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Confluent.Kafka;
using KafkaFlow;
using KafkaFlow.Sample.CooperativeSticky;
using KafkaFlow.Serializer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AutoOffsetReset = KafkaFlow.AutoOffsetReset;

const string producerName = "PrintConsole";
const string topicName = "sample-topic";
var hostBuilder = new HostBuilder();
hostBuilder.ConfigureServices(services =>
services.AddHostedService<HostedService>().AddKafka(
kafka => kafka
.UseConsoleLog()
.AddCluster(
cluster => cluster
.WithBrokers(new[] { "localhost:9092" })
.CreateTopicIfNotExists(topicName, 6, 1)
.AddProducer(
producerName,
producer => producer
.DefaultTopic(topicName)
.AddMiddlewares(m => m.AddSerializer<ProtobufNetSerializer>())
)
.AddConsumer(
consumer => consumer
.WithConsumerConfig(new ConsumerConfig
{
PartitionAssignmentStrategy = PartitionAssignmentStrategy.CooperativeSticky})
.Topic(topicName)
.WithGroupId("print-console-handler")
.WithBufferSize(100)
.WithWorkersCount(3)
.WithAutoCommitIntervalMs(100)
.WithAutoOffsetReset(AutoOffsetReset.Latest)
.AddMiddlewares(
middlewares => middlewares
.AddDeserializer<ProtobufNetDeserializer>()
.AddTypedHandlers(h => h.AddHandler<PrintConsoleHandler>())
)
)
)
));

var build = hostBuilder.Build();
var kafkaBus = build.Services.CreateKafkaBus();
await kafkaBus.StartAsync();

await build.RunAsync();
await kafkaBus.StopAsync();
28 changes: 28 additions & 0 deletions samples/KafkaFlow.Sample.CooperativeSticky/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# KafkaFlow.Sample

This is a simple sample that shows how to produce and consume messages.

## How to run

### Requirements

- [.NET 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)

### Start the cluster

Using your terminal of choice, start the cluster.
You can find a docker-compose file at the root of this repository.
Position the terminal in that folder and run the following command.

```bash
docker-compose up -d
```

### Run the Sample

Using your terminal of choice, start the sample for the sample folder.

```bash
dotnet run
```
10 changes: 10 additions & 0 deletions samples/KafkaFlow.Sample.CooperativeSticky/TestMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Runtime.Serialization;

namespace KafkaFlow.Sample.CooperativeSticky;

[DataContract]
public class TestMessage
{
[DataMember(Order = 1)]
public string Text { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public IConsumerConfiguration Build(ClusterConfiguration clusterConfiguration)

consumerConfigCopy.EnableAutoOffsetStore = false;
consumerConfigCopy.EnableAutoCommit = _consumerConfig.PartitionAssignmentStrategy.IsStopTheWorldStrategy() is false;
consumerConfigCopy.AutoCommitIntervalMs = _consumerConfig.AutoCommitIntervalMs ?? 5000;
consumerConfigCopy.AutoCommitIntervalMs = (int?)_autoCommitInterval.TotalMilliseconds;

consumerConfigCopy.ReadSecurityInformationFrom(clusterConfiguration);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using AutoFixture;
using AutoFixture.AutoMoq;
using Confluent.Kafka;
using FluentAssertions;
using KafkaFlow.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace KafkaFlow.UnitTests.Consumer;

[TestClass]
public class ConsumerConfigurationBuilderTests
{
private readonly Fixture _fixture = new();

[TestInitialize]
public void Setup()
{
_fixture.Customize(new AutoMoqCustomization());
}

[TestMethod]
public void ConfigurationBuild_CallBuild_WithSticky_EnableAutoCommit_True()
{
// Arrange
var consumerConfigurationBuilder = _fixture.Create<ConsumerConfigurationBuilder>();
consumerConfigurationBuilder.WithConsumerConfig(new ConsumerConfig
{
PartitionAssignmentStrategy = PartitionAssignmentStrategy.CooperativeSticky,
GroupId = "Test",
}).WithAutoCommitIntervalMs(500)
.WithBufferSize(3);

// Act
var consumerConfiguration = consumerConfigurationBuilder.Build(_fixture.Create<ClusterConfiguration>());

// Assert
var consumerConfig = consumerConfiguration.GetKafkaConfig();
consumerConfig.EnableAutoCommit.Should().BeTrue();
consumerConfig.AutoCommitIntervalMs.Should().Be(500);
consumerConfiguration.AutoCommitInterval.Should().Be(TimeSpan.FromMilliseconds(500));
}

[TestMethod]
public void ConfigurationBuild_CallBuild_WithSRoundRobin_EnableAutoCommit_False()
{
// Arrange
var consumerConfigurationBuilder = new ConsumerConfigurationBuilder(Mock.Of<IDependencyConfigurator>());
consumerConfigurationBuilder.WithConsumerConfig(new ConsumerConfig
{
PartitionAssignmentStrategy = PartitionAssignmentStrategy.RoundRobin,
GroupId = "Test"
}).WithAutoCommitIntervalMs(500).WithBufferSize(3);
// Act
var consumerConfiguration = consumerConfigurationBuilder.Build(_fixture.Create<ClusterConfiguration>());

// Assert
consumerConfiguration.GetKafkaConfig().EnableAutoCommit.Should().BeFalse();
consumerConfiguration.AutoCommitInterval.Should().Be(TimeSpan.FromMilliseconds(500));
}
}
Loading

0 comments on commit 83bce82

Please sign in to comment.