Skip to content

Commit

Permalink
Change AccountService from go to dotnet (auto)
Browse files Browse the repository at this point in the history
  • Loading branch information
RassK committed Apr 19, 2024
1 parent 307f379 commit 72fefeb
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 326 deletions.
29 changes: 29 additions & 0 deletions src/accountingservice/AccountingService.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Confluent.Kafka" Version="2.3.0" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes.Protobuf" Version="2.3.0" />
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
<PackageReference Include="Grpc.Tools" Version="2.62.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
<PackageReference Include="OpenTelemetry.AutoInstrumentation" Version="1.5.0" />
</ItemGroup>

<ItemGroup>
<!-- GrpcServices is 'none' so that we do not need to depend on the grpc nuget package, and we only need protobuf support. -->
<Protobuf Include="..\..\pb\demo.proto" GrpcServices="none" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions src/accountingservice/AccountingService.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34701.34
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccountingService", "AccountingService.csproj", "{C66C35E2-DF04-4DCF-8F6A-87B6D6433FF6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C66C35E2-DF04-4DCF-8F6A-87B6D6433FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C66C35E2-DF04-4DCF-8F6A-87B6D6433FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C66C35E2-DF04-4DCF-8F6A-87B6D6433FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C66C35E2-DF04-4DCF-8F6A-87B6D6433FF6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6340CDDC-E917-4532-A056-5526E0A7BDDA}
EndGlobalSection
EndGlobal
89 changes: 89 additions & 0 deletions src/accountingservice/Consumer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Confluent.Kafka;
using Confluent.Kafka.SyncOverAsync;
using Confluent.SchemaRegistry.Serdes;
using Microsoft.Extensions.Logging;
using Oteldemo;

namespace AccountingService;

internal class Consumer : IDisposable
{
private const string TopicName = "orders";

private ILogger _logger;
private IConsumer<string, OrderResult> _consumer;
private bool _isListening;

public Consumer(ILogger<Consumer> logger)
{
_logger = logger;

var servers = Environment.GetEnvironmentVariable("KAFKA_SERVICE_ADDR")
?? throw new ArgumentNullException("KAFKA_SERVICE_ADDR");

_consumer = BuildConsumer(servers);
_consumer.Subscribe(TopicName);

_logger.LogInformation($"Connecting to Kafka: {servers}");
}

public void StartListening()
{
_isListening = true;

try
{
while (_isListening)
{
try
{
var consumeResult = _consumer.Consume();
if (consumeResult.IsPartitionEOF)
{
continue;
}

ProcessMessage(consumeResult.Message);
}
catch (ConsumeException e)
{
_logger.LogError(e, "Consume error: {0}", e.Error.Reason);
}
}
}
catch (OperationCanceledException)
{
_logger.LogInformation("Closing consumer");

_consumer.Close();
}
}

private void ProcessMessage(Message<string, OrderResult> message)
{
Log.LogOrderReceivedMessage(_logger, message.Value);
}

private IConsumer<string, OrderResult> BuildConsumer(string servers)
{
var conf = new ConsumerConfig
{
GroupId = $"accountingservice",
BootstrapServers = servers,
// https://github.com/confluentinc/confluent-kafka-dotnet/tree/07de95ed647af80a0db39ce6a8891a630423b952#basic-consumer-example
AutoOffsetReset = AutoOffsetReset.Earliest,
CancellationDelayMaxMs = 10_000,
EnableAutoCommit = true
};

return new ConsumerBuilder<string, OrderResult>(conf)
.SetValueDeserializer(new ProtobufDeserializer<OrderResult>().AsSyncOverAsync())
.Build();
}

public void Dispose()
{
_isListening = false;
_consumer?.Dispose();
}
}
64 changes: 32 additions & 32 deletions src/accountingservice/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0


FROM golang:1.22-alpine AS builder

WORKDIR /usr/src/app

RUN apk update \
&& apk add --no-cache make protobuf-dev

RUN --mount=type=cache,target=/go/pkg/mod/ \
--mount=type=bind,source=./src/accountingservice/go.sum,target=go.sum \
--mount=type=bind,source=./src/accountingservice/go.mod,target=go.mod \
--mount=type=bind,source=./src/accountingservice/tools.go,target=tools.go \
go mod download \
&& go list -e -f '{{range .Imports}}{{.}} {{end}}' tools.go | CGO_ENABLED=0 xargs go install -mod=readonly

RUN --mount=type=cache,target=/go/pkg/mod/ \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=bind,rw,source=./src/accountingservice,target=. \
--mount=type=bind,rw,source=./pb,target=./pb \
protoc -I ./pb ./pb/demo.proto --go_out=./ --go-grpc_out=./ \
&& go build -ldflags "-s -w" -o /go/bin/accountingservice/ ./

FROM alpine

WORKDIR /usr/src/app/

COPY --from=builder /go/bin/accountingservice/ ./

ENTRYPOINT [ "./accountingservice" ]
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["AccountingService/AccountingService.csproj", "AccountingService/"]
RUN dotnet restore "./AccountingService/AccountingService.csproj"
COPY . .
WORKDIR "/src/AccountingService"
RUN dotnet build "./AccountingService.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./AccountingService.csproj" --use-current-runtime -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

USER root
RUN mkdir -p "/var/log/opentelemetry/dotnet"
RUN chown app "/var/log/opentelemetry/dotnet"
USER app

ENV OTEL_TRACES_EXPORTER=otlp
ENV OTEL_METRICS_EXPORTER=none
ENV OTEL_LOGS_EXPORTER=otlp
ENV OTEL_LOG_LEVEL=debug

ENTRYPOINT ["./instrument.sh", "dotnet", "AccountingService.dll"]
31 changes: 31 additions & 0 deletions src/accountingservice/Helpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections;

namespace AccountingService
{
internal static class Helpers
{
private static List<string> RelevantPrefixes = ["DOTNET_", "CORECLR_", "OTEL_", "KAFKA_"];

public static IEnumerable<DictionaryEntry> FilterRelevant(this IDictionary envs)
{
foreach (DictionaryEntry env in envs)
{
foreach (var prefix in RelevantPrefixes)
{
if (env.Key.ToString()?.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase) ?? false)
{
yield return env;
}
}
}
}

public static void OutputInOrder(this IEnumerable<DictionaryEntry> envs)
{
foreach (var env in envs.OrderBy(x => x.Key))
{
Console.WriteLine(env);
}
}
}
}
13 changes: 13 additions & 0 deletions src/accountingservice/Log.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.Extensions.Logging;
using Oteldemo;

namespace AccountingService
{
internal static partial class Log
{
[LoggerMessage(
Level = LogLevel.Information,
Message = "Order details: {@OrderResult}.")]
public static partial void LogOrderReceivedMessage(ILogger logger, OrderResult orderResult);
}
}
21 changes: 21 additions & 0 deletions src/accountingservice/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using AccountingService;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Console.WriteLine("Accounting service started");

Environment.GetEnvironmentVariables()
.FilterRelevant()
.OutputInOrder();

var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddSingleton<Consumer>();
})
.Build();

var consumer = host.Services.GetRequiredService<Consumer>();
consumer.StartListening();

host.Run();
18 changes: 3 additions & 15 deletions src/accountingservice/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This service consumes new orders from a Kafka topic.
To build the service binary, run:

```sh
go build -o /go/bin/accountingservice/
dotnet build
```

## Docker Build
Expand All @@ -18,22 +18,10 @@ From the root directory, run:
docker compose build accountingservice
```

## Regenerate protos

> [!NOTE]
> [`protoc`](https://grpc.io/docs/protoc-installation/) is required.
To regenerate gRPC code run:

```sh
go generate
```

## Bump dependencies

To bump all dependencies run:
To bump all dependencies run in Package manager:

```sh
go get -u -t ./...
go mod tidy
Update-Package -ProjectName AccountingService
```
77 changes: 0 additions & 77 deletions src/accountingservice/kafka/consumer.go

This file was deleted.

Loading

0 comments on commit 72fefeb

Please sign in to comment.