internal Producer(ProducerBuilder <TKey, TValue> builder) { var baseConfig = builder.ConstructBaseConfig(this); // TODO: Make Tasks auto complete when EnableDeliveryReportsPropertyName is set to false. // TODO: Hijack the "delivery.report.only.error" configuration parameter and add functionality to enforce that Tasks // that never complete are never created when this is set to true. this.statisticsHandler = baseConfig.statisticsHandler; this.logHandler = baseConfig.logHandler; this.errorHandler = baseConfig.errorHandler; var config = Confluent.Kafka.Config.ExtractCancellationDelayMaxMs(baseConfig.config, out this.cancellationDelayMaxMs); this.DeliveryReportCallback = DeliveryReportCallbackImpl; Librdkafka.Initialize(null); var modifiedConfig = config .Where(prop => prop.Key != ConfigPropertyNames.Producer.EnableBackgroundPoll && prop.Key != ConfigPropertyNames.Producer.EnableDeliveryReports && prop.Key != ConfigPropertyNames.Producer.DeliveryReportFields); if (modifiedConfig.Where(obj => obj.Key == "delivery.report.only.error").Count() > 0) { // A managed object is kept alive over the duration of the produce request. If there is no // delivery report generated, there will be a memory leak. We could possibly support this // property by keeping track of delivery reports in managed code, but this seems like // more trouble than it's worth. throw new ArgumentException("The 'delivery.report.only.error' property is not supported by this client"); } var enableBackgroundPollObj = config.FirstOrDefault(prop => prop.Key == ConfigPropertyNames.Producer.EnableBackgroundPoll).Value; if (enableBackgroundPollObj != null) { this.manualPoll = !bool.Parse(enableBackgroundPollObj); } var enableDeliveryReportsObj = config.FirstOrDefault(prop => prop.Key == ConfigPropertyNames.Producer.EnableDeliveryReports).Value; if (enableDeliveryReportsObj != null) { this.enableDeliveryReports = bool.Parse(enableDeliveryReportsObj); } var deliveryReportEnabledFieldsObj = config.FirstOrDefault(prop => prop.Key == ConfigPropertyNames.Producer.DeliveryReportFields).Value; if (deliveryReportEnabledFieldsObj != null) { var fields = deliveryReportEnabledFieldsObj.Replace(" ", ""); if (fields != "all") { this.enableDeliveryReportKey = false; this.enableDeliveryReportValue = false; this.enableDeliveryReportHeaders = false; this.enableDeliveryReportTimestamp = false; this.enableDeliveryReportPersistedStatus = false; if (fields != "none") { var parts = fields.Split(','); foreach (var part in parts) { switch (part) { case "key": this.enableDeliveryReportKey = true; break; case "value": this.enableDeliveryReportValue = true; break; case "timestamp": this.enableDeliveryReportTimestamp = true; break; case "headers": this.enableDeliveryReportHeaders = true; break; case "status": this.enableDeliveryReportPersistedStatus = true; break; default: throw new ArgumentException( $"Unknown delivery report field name '{part}' in config value '{ConfigPropertyNames.Producer.DeliveryReportFields}'."); } } } } } var configHandle = SafeConfigHandle.Create(); modifiedConfig.ToList().ForEach((kvp) => { if (kvp.Value == null) { throw new ArgumentNullException($"'{kvp.Key}' configuration parameter must not be null."); } configHandle.Set(kvp.Key, kvp.Value); }); IntPtr configPtr = configHandle.DangerousGetHandle(); if (enableDeliveryReports) { Librdkafka.conf_set_dr_msg_cb(configPtr, DeliveryReportCallback); } // Explicitly keep references to delegates so they are not reclaimed by the GC. errorCallbackDelegate = ErrorCallback; logCallbackDelegate = LogCallback; statisticsCallbackDelegate = StatisticsCallback; if (errorHandler != null) { Librdkafka.conf_set_error_cb(configPtr, errorCallbackDelegate); } if (logHandler != null) { Librdkafka.conf_set_log_cb(configPtr, logCallbackDelegate); } if (statisticsHandler != null) { Librdkafka.conf_set_stats_cb(configPtr, statisticsCallbackDelegate); } this.ownedKafkaHandle = SafeKafkaHandle.Create(RdKafkaType.Producer, configPtr, this); configHandle.SetHandleAsInvalid(); // config object is no longer useable. if (!manualPoll) { callbackCts = new CancellationTokenSource(); callbackTask = StartPollTask(callbackCts.Token); } InitializeSerializers( builder.KeySerializer, builder.ValueSerializer, builder.AsyncKeySerializer, builder.AsyncValueSerializer); }