confluent-kafka-dotnet icon indicating copy to clipboard operation
confluent-kafka-dotnet copied to clipboard

.NET 8 and Native AOT approach

Open AlexanderPopovSLIC opened this issue 1 year ago • 2 comments

Description

If I publish my code in Native AOT then all parts of code which are related to Kafka usage (such as: Producers and Consumers) stopped working. I have got the next message in Console after running published to native AOT app

Unhandled Exception: System.InvalidOperationException: Sequence contains no matching element
   at System.Linq.ThrowHelper.ThrowNoMatchException() + 0x2b
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1, Func`2) + 0x27
   at Confluent.Kafka.Impl.Librdkafka.SetDelegates(Type) + 0xdb
   at Confluent.Kafka.Impl.Librdkafka.TrySetDelegates(List`1) + 0x16
   at Confluent.Kafka.Impl.Librdkafka.LoadNetStandardDelegates(String) + 0xb2
   at Confluent.Kafka.Impl.Librdkafka.Initialize(String) + 0xd0
   at Confluent.Kafka.Producer`2..ctor(ProducerBuilder`2) + 0x19d
   at BLL.Core.KafkaService..ctor(IServiceProvider serviceProvider) + 0x1f5
   at WebApplication1!<BaseAddress>+0xcf395d
   at System.Reflection.DynamicInvokeInfo.InvokeWithFewArguments(IntPtr, Byte&, Byte&, Object[], BinderBundle, Boolean) + 0x95
   at System.Reflection.DynamicInvokeInfo.Invoke(Object, IntPtr, Object[], BinderBundle, Boolean) + 0x11d
   at Internal.Reflection.Execution.MethodInvokers.InstanceMethodInvoker.CreateInstance(Object[], BinderBundle, Boolean) + 0x44
   at Internal.Reflection.Core.Execution.MethodBaseInvoker.CreateInstance(Object[], Binder, BindingFlags, CultureInfo) + 0x3b
   at System.Reflection.Runtime.MethodInfos.RuntimePlainConstructorInfo`1.Invoke(BindingFlags, Binder, Object[], CultureInfo) + 0x55

I'm using a very simple code which works in regular published app:

IDictionary<string, string> config = new Dictionary<string, string>()
{
    { "bootstrap.servers", BootstrapServers },
    { "socket.max.fails", "0" },
    { "message.send.max.retries", "10" },
    { "batch.num.messages", "1000000" },
    { "queue.buffering.max.ms", "1" },
    { "request.timeout.ms", "2000" },
    { "message.timeout.ms", "5000" },
    { "client.id", Dns.GetHostName() }
};

//     -->  This line of code throws an exception  <--
_producer = new ProducerBuilder<Null, byte[]>(new ProducerConfig(config)).Build();

OS -> Windows 11

Nuget package is the latest one on the current moment Confluent.Kafka, Version=2.3.0.0, Culture=neutral, PublicKeyToken=12c514ca49093d1e

How to reproduce

  1. Create a new ConsolApp project (.NET 8) using Visual Studio, VS Code, or just using terminal
  2. Install Nuget package (Confluent.Kafks 2.3.0.0)
  3. Add the next lines into .csproj file
<PublishAot>true</PublishAot>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishTrimmed>true</PublishTrimmed>
  1. Use my code I provided above to try to create Producer (there are required minimum changes)
  2. Publish App using the next command (terminal should be open from the path where .csproj file is located) dotnet publish -c Release -o "otput_path_where_app_will_be_published"
  3. Run published app and check the error

Checklist

Please provide the following information:

  • [x] A complete (i.e. we can run it), minimal program demonstrating the problem. No need to supply a project file.
  • [x] Confluent.Kafka nuget version.
  • [ ] Apache Kafka version.
  • [ ] Client configuration.
  • [x] Operating system.
  • [ ] Provide logs (with "debug" : "..." as necessary in configuration).
  • [ ] Provide broker log excerpts.
  • [ ] Critical issue.

AlexanderPopovSLIC avatar Nov 30 '23 22:11 AlexanderPopovSLIC

Hello, not sure if it will help but I managed to make it work on windows aot by changing only one line

        private static void LoadNetStandardDelegates(string userSpecifiedPath)
        {
            if (userSpecifiedPath != null)
            {
                if (WindowsNative.LoadLibraryEx(userSpecifiedPath, IntPtr.Zero, WindowsNative.LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH) == IntPtr.Zero)
                {
                    // TODO: The Win32Exception class is not available in .NET Standard, which is the easy way to get the message string corresponding to
                    // a win32 error. FormatMessage is not straightforward to p/invoke, so leaving this as a job for another day.
                    throw new InvalidOperationException($"Failed to load librdkafka at location '{userSpecifiedPath}'. Win32 error: {Marshal.GetLastWin32Error()}");
                }
            }

-            TrySetDelegates(new List<Type> { typeof(NativeMethods.NativeMethods) });
+            SetDelegates(typeof(NativeMethods.NativeMethods));
        }

latop2604 avatar Jan 19 '24 18:01 latop2604

Having the same issue here (Publishing as trimmed, no AOT).

BoutemineOualid avatar Jan 21 '24 20:01 BoutemineOualid