public KafkaOutput(KafkaLoggingOptions options) : base(options.BufferedOutputOptions)
        {
            if (string.IsNullOrWhiteSpace(options.Topic))
            {
                throw new ArgumentException("Must not empty", $"{nameof(options)}.{nameof(options.Topic)}");
            }

            if (options.Serializer == null)
            {
                throw new ArgumentException("Must not null", $"{nameof(options)}.{nameof(options.Serializer)}");
            }

            _options = options;

            if (!string.IsNullOrWhiteSpace(_options.ContentType))
            {
                _headers.Add("Content-Type", Encoding.UTF8.GetBytes(_options.ContentType));
            }

            var pb = new ProducerBuilder <Guid, IReadOnlyDictionary <string, object?> >(_options.ProducerConfig)
                     .SetKeySerializer(new GuiSerializer())
                     .SetValueSerializer(new ObjectSerializer(_options.Serializer));

            if (_options.KafkaErrorHandler != null)
            {
                var handler = _options.KafkaErrorHandler;
                pb.SetErrorHandler((_, error) => handler(error));
            }

            _producer = pb.Build();
        }
예제 #2
0
        public IProducer <Null, byte[]> CreateProducer(
            KafkaQueueConfiguration config,
            Action <IProducer <Null, byte[]>, LogMessage> logHandler = null,
            Action <IProducer <Null, byte[]>, Error> errorHandler    = null)
        {
            config.ThrowIfNull(nameof(config));

            var builder = new ProducerBuilder <Null, byte[]>(new ProducerConfig
            {
                BootstrapServers        = $"{config.Server}",
                SaslKerberosKeytab      = config.KeyTab,
                SaslKerberosPrincipal   = config.User,
                SaslKerberosServiceName = config.ServiceName,
                SecurityProtocol        = config.Protocol,
                SaslMechanism           = config.Mechanism,
                Debug = config.Debug
            });

            if (logHandler != null)
            {
                builder.SetLogHandler(logHandler);
            }
            if (errorHandler != null)
            {
                builder.SetErrorHandler(errorHandler);
            }

            return(builder.Build());
        }
예제 #3
0
        private void Init(ProducerConfig config)
        {
            if (_logger.IsDebug)
            {
                _logger.Debug($"Initializing {Name} type producer for Kafka...");
            }
            try
            {
                CachedSchemaRegistryClient schemaRegistry = new CachedSchemaRegistryClient(new[]
                {
                    new KeyValuePair <string, string>(SchemaRegistryConfig.PropertyNames.SchemaRegistryUrl, _schemaRegistryUrl)
                });

                var blockAvroSerializer = new AvroSerializer <Block>(schemaRegistry).AsSyncOverAsync();
                var txAvroSerializer    = new AvroSerializer <FullTransaction>(schemaRegistry).AsSyncOverAsync();
                ProducerBuilder <Null, Block> blockProducerBuilder = new ProducerBuilder <Null, Block>(config);
                blockProducerBuilder.SetValueSerializer(blockAvroSerializer);
                blockProducerBuilder.SetErrorHandler((s, e) => _logger.Error(e.ToString()));
                ProducerBuilder <Null, FullTransaction> txProducerBuilder = new ProducerBuilder <Null, FullTransaction>(config);
                txProducerBuilder.SetValueSerializer(txAvroSerializer);
                txProducerBuilder.SetErrorHandler((s, e) => _logger.Error(e.ToString()));

                _producerBlocks       = blockProducerBuilder.Build();
                _producerTransactions = txProducerBuilder.Build();
                _initialized          = true;
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Initialized {Name} type producer for Kafka.");
                }
            }
            catch (Exception e)
            {
                _logger.Error(e.Message, e);
            }
        }
예제 #4
0
        public static void Producer()
        {
            var config = new ProducerConfig {
                BootstrapServers = mBootstrapServers
            };
            Action <DeliveryReport <Null, string> > handler = r =>
                                                              Console.WriteLine(!r.Error.IsError
                ? $"Delivered message to {r.TopicPartitionOffset}"
                : $"Delivery Error: {r.Error.Reason}");
            var producerBuilder = new ProducerBuilder <Null, string>(config);

            // 错误日志监视
            producerBuilder.SetErrorHandler((p, msg) =>
            {
                Console.WriteLine($"Producer_Erro信息:Code:{msg.Code};Reason:{msg.Reason};IsError:{msg.IsError}");
            });

            using (var producer = producerBuilder.Build())
            {
                for (int i = 0; i < 5; i++)
                {
                    // 异步发送消息到主题
                    producer.Produce(mTopick, new Message <Null, string> {
                        Value = i.ToString()
                    }, handler);
                }
                // 3后 Flush到磁盘
                producer.Flush(TimeSpan.FromSeconds(3));
            }
        }
예제 #5
0
        public IProducer <string, string> Create()
        {
            var config  = new ProducerConfig(_configuration.GetProducerConfiguration());
            var builder = new ProducerBuilder <string, string>(config);

            builder.SetErrorHandler(OnKafkaError);
            return(builder.Build());
        }
예제 #6
0
        public IProducer <byte[], byte[]> GetProducer(ProducerConfig config)
        {
            ProducerBuilder <byte[], byte[]> builder = new ProducerBuilder <byte[], byte[]>(config);

            builder.SetLogHandler(loggerAdapter.LogProduce);
            builder.SetErrorHandler(loggerAdapter.ErrorProduce);
            return(builder.Build());
        }
예제 #7
0
 public KafkaProducer(IKafkaConfig config, K serializer)
 {
     _config       = config;
     _serializer   = serializer;
     _producerBldr = new ProducerBuilder <Null, string>(_config.ProducerConfig());
     _producerBldr.SetErrorHandler(ErrorHandler);
     _producer = _producerBldr.Build();
 }
예제 #8
0
        private static ProducerBuilder <T, TV> GetProducerBuilderInstance <T, TV>(ProducerConfig configuration) where T : class where TV : class
        {
            var producer = new ProducerBuilder <T, TV>(configuration);

            producer.SetErrorHandler((_, e) => Devon4NetLogger.Error(new ConsumerException($"Error code {e.Code} : {e.Reason}")));
            producer.SetStatisticsHandler((_, json) => Devon4NetLogger.Information($"Statistics: {json}"));
            producer.SetLogHandler((c, partitions) => { Devon4NetLogger.Information($"Kafka log handler: [{string.Join(", ", partitions)}]"); });
            return(producer);
        }
예제 #9
0
 public KafkaProducerContext(ProducerBuilder <TKey, TValue> producerBuilder, IHeadersSerializer headersSerializer, ILogContext logContext,
                             CancellationToken cancellationToken)
     : base(cancellationToken)
 {
     _logContext = logContext;
     _producer   = producerBuilder
                   .SetErrorHandler(OnError)
                   .Build();
     _cancellationTokenSource = new CancellationTokenSource();
     HeadersSerializer        = headersSerializer;
 }
예제 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="KafkaSender"/> class.
        /// </summary>
        /// <param name="name">The name of the sender.</param>
        /// <param name="topic">
        /// The topic to produce messages to.
        /// </param>
        /// <param name="bootstrapServers">
        /// List of brokers as a CSV list of broker host or host:port.
        /// </param>
        /// <param name="messageTimeoutMs">
        /// Local message timeout. This value is only enforced locally and limits the time
        /// a produced message waits for successful delivery. A time of 0 is infinite. This
        /// is the maximum time librdkafka may use to deliver a message (including retries).
        /// Delivery error occurs when either the retry count or the message timeout are
        /// exceeded.
        /// </param>
        /// <param name="config">
        /// A collection of librdkafka configuration parameters (refer to
        /// https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) and parameters
        /// specific to this client (refer to: Confluent.Kafka.ConfigPropertyNames).
        /// </param>
        public KafkaSender(string name, string topic, string bootstrapServers, int messageTimeoutMs = 10000, ProducerConfig config = null)
        {
            Name   = name ?? throw new ArgumentNullException(nameof(name));
            Topic  = topic ?? throw new ArgumentNullException(nameof(topic));
            Config = config ?? new ProducerConfig();
            Config.BootstrapServers = bootstrapServers ?? throw new ArgumentNullException(nameof(bootstrapServers));
            Config.MessageTimeoutMs = Config.MessageTimeoutMs ?? messageTimeoutMs;

            var producerBuilder = new ProducerBuilder <Null, string>(Config);

            producerBuilder.SetErrorHandler(OnError);

            _producer = new Lazy <IProducer <Null, string> >(() => producerBuilder.Build());
        }
예제 #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="KafkaSender"/> class.
        /// </summary>
        /// <param name="name">The name of the sender.</param>
        /// <param name="topic">The topic to produce messages to.</param>
        /// <param name="bootstrapServers">List of brokers as a CSV list of broker host or host:port.</param>
        /// <param name="messageTimeoutMs">
        /// Local message timeout. This value is only enforced locally and limits the time
        /// a produced message waits for successful delivery. A time of 0 is infinite. This
        /// is the maximum time librdkafka may use to deliver a message (including retries).
        /// Delivery error occurs when either the retry count or the message timeout are
        /// exceeded.
        /// </param>
        public KafkaSender(string name, string topic, string bootstrapServers, int messageTimeoutMs = 10000)
        {
            Name             = name ?? throw new ArgumentNullException(nameof(name));
            Topic            = topic ?? throw new ArgumentNullException(nameof(topic));
            BootstrapServers = bootstrapServers ?? throw new ArgumentNullException(nameof(bootstrapServers));
            MessageTimeoutMs = messageTimeoutMs;

            var config = GetProducerConfig(bootstrapServers, messageTimeoutMs);

            var producerBuilder = new ProducerBuilder <string, byte[]>(config);

            producerBuilder.SetErrorHandler(OnError);

            _producer = new Lazy <IProducer <string, byte[]> >(() => producerBuilder.Build());
        }
예제 #12
0
        private static void AddKafkaProducer(this IServiceCollection services)
        {
            services.AddTransient(p =>
            {
                var logger          = p.GetService <ILogger <IProducer <string, IIntegrationEvent> > >();
                var kafkaOptions    = p.GetService <IOptions <KafkaOptions> >();
                var producerBuilder = new ProducerBuilder <string, IIntegrationEvent>(kafkaOptions.Value.Configuration);
                var producer        = producerBuilder.SetErrorHandler((_, e) => logger.LogError($"Error: {e?.Reason}", e))
                                      .SetStatisticsHandler((_, json) => logger.LogDebug($"Statistics: {json}"))
                                      .SetValueSerializer(new DefaultValueSerializer <IIntegrationEvent>())
                                      .Build();

                return(producer);
            });
        }
예제 #13
0
        public async Task ProduceAsync(string channelName, MessageBrokerMessage message)
        {
            var config = new ProducerConfig {
                BootstrapServers = _serverAddress
            };

            var producerBuilder = new ProducerBuilder <string, string>(config);

            producerBuilder.SetErrorHandler(
                (producer, error) => { _logger.LogWarning(error.Reason); }
                );

            try
            {
                while (true)
                {
                    try
                    {
                        using (var producer = producerBuilder.Build())
                        {
                            // Note: Awaiting the asynchronous produce request below prevents flow of execution
                            // from proceeding until the acknowledgement from the broker is received (at the
                            // expense of low throughput).

                            var deliveryReport = await producer.ProduceAsync(
                                channelName, KafkaMessage.FromMessageBrokerMessage(message)
                                );

                            //producer.Produce(
                            //    channelName, KafkaMessage.FromMessageBrokerMessage(message)
                            //);


                            //_logger.LogInformation($"delivered to: {deliveryReport.TopicPartitionOffset}");
                            return;
                        }
                    }
                    catch (KafkaException e)
                    {
                        _logger.LogError($"failed to deliver message: {e.Message} [{e.Error.Code}]");
                    }
                }
            }
            catch (OperationCanceledException)
            {
                //
            }
        }
예제 #14
0
        /// <summary>
        /// producer构造器
        /// </summary>
        /// <returns></returns>
        private ProducerBuilder <string, object> CreateProducerBuilder()
        {
            if (builder == null)
            {
                lock (this)
                {
                    if (builder == null)
                    {
                        ProducerConfig config = new ProducerConfig();
                        config.BootstrapServers = BootstrapServers;
                        if (!string.IsNullOrEmpty(SaslUsername))
                        {
                            config.SaslUsername     = SaslUsername;
                            config.SaslPassword     = SaslPassword;
                            config.SaslMechanism    = SaslMechanism.Plain;
                            config.SecurityProtocol = SecurityProtocol.SaslPlaintext;
                        }

                        //List<KeyValuePair<string, string>> config = new List<KeyValuePair<string, string>>();
                        //config.Add(new KeyValuePair<string, string>("bootstrap.servers", BootstrapServers));
                        //if (!string.IsNullOrEmpty(SaslUsername))
                        //{
                        //    config.Add(new KeyValuePair<string, string>("security.protocol", "SASL_PLAINTEXT"));
                        //    config.Add(new KeyValuePair<string, string>("sasl.mechanism", "PLAIN"));
                        //    config.Add(new KeyValuePair<string, string>("sasl.username", SaslUsername));
                        //    config.Add(new KeyValuePair<string, string>("sasl.password", SaslPassword));
                        //}

                        builder = new ProducerBuilder <string, object>(config);
                        Action <Delegate, object> tryCatchWrap = (@delegate, arg) =>
                        {
                            try
                            {
                                @delegate?.DynamicInvoke(arg);
                            }
                            catch { }
                        };
                        builder.SetErrorHandler((p, e) => tryCatchWrap(ErrorHandler, new Exception(e.Reason)));
                        builder.SetStatisticsHandler((p, e) => tryCatchWrap(StatisticsHandler, e));
                        builder.SetLogHandler((p, e) => tryCatchWrap(LogHandler, new KafkaLogMessage(e)));
                        builder.SetValueSerializer(new KafkaConverter());
                    }
                }
            }

            return(builder);
        }
예제 #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="KafkaSender"/> class.
        /// </summary>
        /// <param name="name">The name of the sender.</param>
        /// <param name="topic">The topic to produce messages to.</param>
        /// <param name="producerConfig">The configuration used in creation of the Kafka producer.</param>
        public KafkaSender(string name, string topic, ProducerConfig producerConfig)
        {
            if (producerConfig is null)
            {
                throw new ArgumentNullException(nameof(producerConfig));
            }

            Name             = name ?? throw new ArgumentNullException(nameof(name));
            Topic            = topic ?? throw new ArgumentNullException(nameof(topic));
            BootstrapServers = producerConfig.BootstrapServers;
            MessageTimeoutMs = producerConfig.MessageTimeoutMs;

            var producerBuilder = new ProducerBuilder <string, byte[]>(producerConfig);

            producerBuilder.SetErrorHandler(OnError);

            _producer = new Lazy <IProducer <string, byte[]> >(() => producerBuilder.Build());
        }
예제 #16
0
 private void Init(ProducerConfig config)
 {
     if (_logger.IsDebug)
     {
         _logger.Debug($"Initializing {Name} type producer for Kafka...");
     }
     try
     {
         var producerBuilder = new ProducerBuilder <Null, byte[]>(config);
         producerBuilder.SetErrorHandler((s, e) => _logger.Error(e.ToString()));
         _producer    = producerBuilder.Build();
         _initialized = true;
         if (_logger.IsDebug)
         {
             _logger.Debug($"Initialized {Name} type producer for Kafka.");
         }
     }
     catch (Exception e)
     {
         _logger.Error(e.Message, e);
     }
 }
예제 #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="KafkaSender"/> class.
        /// </summary>
        /// <param name="name">The name of the sender.</param>
        /// <param name="topic">The topic to produce messages to.</param>
        /// <param name="schemaId">
        /// The schema ID to have the broker validate messages against. The sender will prepend a leading empty byte
        /// and the schema ID to the payload according to the Confluent
        /// <a href="https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#wire-format">wire format</a>.
        /// </param>
        /// <param name="bootstrapServers">List of brokers as a CSV list of broker host or host:port.</param>
        /// <param name="messageTimeoutMs">
        /// Local message timeout. This value is only enforced locally and limits the time
        /// a produced message waits for successful delivery. A time of 0 is infinite. This
        /// is the maximum time librdkafka may use to deliver a message (including retries).
        /// Delivery error occurs when either the retry count or the message timeout are
        /// exceeded.
        /// </param>
        /// <param name="statisticsIntervalMs">
        /// The statistics emit interval in milliseconds. Granularity is 1,000ms. An event handler must be attached to the
        /// <see cref="StatisticsEmitted"/> event to receive the statistics data. Setting to 0 disables statistics.
        /// </param>
        public KafkaSender(string name, string topic, int schemaId, string bootstrapServers, int messageTimeoutMs = Constants.DefaultTimeout,
                           int statisticsIntervalMs = 0)
        {
            Name             = name ?? throw new ArgumentNullException(nameof(name));
            Topic            = topic ?? throw new ArgumentNullException(nameof(topic));
            BootstrapServers = bootstrapServers ?? throw new ArgumentNullException(nameof(bootstrapServers));
            MessageTimeoutMs = messageTimeoutMs;

            if (schemaId <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(schemaId), "Should be greater than 0");
            }
            SchemaId = schemaId;

            var config = GetProducerConfig(bootstrapServers, messageTimeoutMs, statisticsIntervalMs);

            var producerBuilder = new ProducerBuilder <string, byte[]>(config);

            producerBuilder.SetErrorHandler(OnError);
            producerBuilder.SetStatisticsHandler(OnStatisticsEmitted);

            _producer = new Lazy <IProducer <string, byte[]> >(() => producerBuilder.Build());
        }
예제 #18
0
        public IProducer <byte[], byte[]> GetProducer(ProducerConfig config)
        {
            ProducerBuilder <byte[], byte[]> builder = builderKafkaHandler.GetProducerBuilder(config);

            builder.SetLogHandler(loggerAdapter.LogProduce);
            builder.SetErrorHandler(loggerAdapter.ErrorProduce);
            if (exposeLibrdKafka)
            {
                // TODO : test librdkafka statistics with IntegrationTest (WIP see #82)
                var producerStatisticsHandler = new ProducerStatisticsHandler(
                    config.ClientId,
                    streamConfig.ApplicationId,
                    (config as StreamizProducerConfig)?.ThreadId,
                    (config as StreamizProducerConfig)?.Id?.ToString());
                producerStatisticsHandler.Register(MetricsRegistry);
                builder.SetStatisticsHandler((c, stat) =>
                {
                    var statistics = JsonConvert.DeserializeObject <Statistics>(stat);
                    producerStatisticsHandler.Publish(statistics);
                });
            }

            return(builder.Build());
        }
예제 #19
0
        public string ProduceMessage(int keyId)
        {
            var message     = $"Producer value-{keyId}";
            var eventToSend = new Event
            {
                id      = Guid.NewGuid().ToString(),
                date    = DateTime.Now.ToString("u"),
                message = new Message
                {
                    header = new Schemas.Header
                    {
                        msg_id   = Guid.NewGuid().ToString(),
                        msg_date = DateTime.Now.ToString("u")
                    },
                    Body = message
                }
            };

            try
            {
                var kafkaConfig = new ProducerConfig {
                    BootstrapServers = Kafka
                };
                var prod = new ProducerBuilder <Key, Event>(kafkaConfig);
                prod.SetErrorHandler(ProducerErrorHandler);
                prod.SetLogHandler(ProducerLogHandler);

                using (var schemaRegistry = new CachedSchemaRegistryClient(_schemaRegistryConfig))
                {
                    prod.SetKeySerializer(new AvroSerializer <Key>(schemaRegistry));
                    prod.SetValueSerializer(new AvroSerializer <Event>(schemaRegistry));

                    using (var p = prod.Build())
                    {
                        try
                        {
                            var dr = p.ProduceAsync("logs", new Message <Key, Event> {
                                Key = new Key {
                                    id = keyId
                                }, Value = eventToSend
                            }).GetAwaiter().GetResult();
                            _logger.LogInformation($"Kafka Producer service delivered the message '{message}' to Topic: {dr.Topic}");
                        }
                        catch (ProduceException <Key, Event> e)
                        {
                            _logger.LogInformation($"Kafka Producer service Delivery failed: {e.Error.Reason}");
                        }
                    }
                }
            }
            catch (OperationCanceledException oce)
            {
                _logger.LogError(oce, "OperationCanceled - Error in delivered message");
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error in delivered message");
                throw;
            }

            return($"The message '{message}' has been sent to the broker.");
        }
예제 #20
0
        public void Start(string instanceId, CancellationToken cancellationToken = default(CancellationToken))
        {
            funcExecSemaphore = new Semaphore(MaxOutstanding, MaxOutstanding);

            CancellationTokenSource errorCts     = new CancellationTokenSource();
            CancellationTokenSource compositeCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, errorCts.Token);
            CancellationToken       compositeCancellationToken = compositeCts.Token;

            bool aMessageHasBeenProcessed = false;

            var cConfig = new ConsumerConfig
            {
                ClientId              = $"{Name}-consumer-{instanceId}",
                GroupId               = $"{Name}-group",
                BootstrapServers      = BootstrapServers,
                EnableAutoCommit      = true,
                EnableAutoOffsetStore = false,
                AutoOffsetReset       = AutoOffsetReset.Latest
            };

            if (DebugContext != null)
            {
                cConfig.Debug = DebugContext;
            }

            var cBuilder = new ConsumerBuilder <TInKey, TInValue>(cConfig);

            if (InKeyDeserializer != null)
            {
                cBuilder.SetKeyDeserializer(InKeyDeserializer);
            }
            if (InValueDeserializer != null)
            {
                cBuilder.SetValueDeserializer(InValueDeserializer);
            }
            if (Logger != null)
            {
                cBuilder.SetLogHandler((_, m) =>
                {
                    Logger(m);
                });
            }

            cBuilder.SetErrorHandler((c, e) =>
            {
                if (e.Code == ErrorCode.Local_AllBrokersDown ||
                    e.Code == ErrorCode.Local_Authentication)
                {
                    if (!aMessageHasBeenProcessed)
                    {
                        // Logger.Log(e);
                        errorCts.Cancel();
                        return;
                    }
                }

                if (Logger != null)
                {
                    Logger(new LogMessage(c.Name, SyslogLevel.Error, "unknown", e.Reason));
                }
            });


            var pConfig = new ProducerConfig
            {
                ClientId             = $"{Name}-producer-{instanceId}",
                BootstrapServers     = BootstrapServers,
                EnableIdempotence    = true,
                LingerMs             = 5,
                DeliveryReportFields = "none"
            };

            if (DebugContext != null)
            {
                pConfig.Debug = DebugContext;
            }

            var pBuilder = new ProducerBuilder <TOutKey, TOutValue>(pConfig);

            if (OutKeySerializer != null)
            {
                pBuilder.SetKeySerializer(OutKeySerializer);
            }
            if (OutValueSerializer != null)
            {
                pBuilder.SetValueSerializer(OutValueSerializer);
            }
            if (Logger != null)
            {
                pBuilder.SetLogHandler((_, m) =>
                {
                    Logger(m);
                });
            }
            pBuilder.SetErrorHandler((p, e) =>
            {
                if (e.IsFatal)
                {
                    errorCts.Cancel();
                    return;
                }

                if (e.Code == ErrorCode.Local_AllBrokersDown ||
                    e.Code == ErrorCode.Local_Authentication)
                {
                    if (!aMessageHasBeenProcessed)
                    {
                        errorCts.Cancel();
                        return;
                    }
                }

                if (Logger != null)
                {
                    Logger(new LogMessage(p.Name, SyslogLevel.Error, "unknown", e.Reason));
                }
            });

            var partitionState = new Dictionary <TopicPartition, PartitionState>();

            using (var producer = pBuilder.Build())
                using (var consumer = cBuilder.Build())
                {
                    consumer.Subscribe(InputTopic);

                    try
                    {
                        while (true)
                        {
                            ConsumeResult <TInKey, TInValue> cr;
                            try
                            {
                                cr = consumer.Consume(compositeCancellationToken);
                            }
                            catch (ConsumeException ex)
                            {
                                if (ex.Error.Code == ErrorCode.Local_ValueDeserialization)
                                {
                                    // For an in-depth discussion of what to do in the event of deserialization errors, refer to:
                                    // https://www.confluent.io/blog/kafka-connect-deep-dive-error-handling-dead-letter-queues

                                    if (ConsumeErrorTolerance == ErrorTolerance.All)
                                    {
                                        continue;
                                    }

                                    errorCts.Cancel(); // no error tolerance.
                                }

                                Thread.Sleep(TimeSpan.FromSeconds(10)); // ?? if not fail fast, do we want to sleep and why?
                                continue;
                            }

                            if (!partitionState.ContainsKey(cr.TopicPartition))
                            {
                                partitionState.Add(cr.TopicPartition, new PartitionState(this));
                            }
                            partitionState[cr.TopicPartition].HandleConsumedMessage(cr, consumer, producer, funcExecSemaphore, errorCts);

                            aMessageHasBeenProcessed = true;
                        }
                    }
                    catch (OperationCanceledException) { }
                }

            if (errorCts.IsCancellationRequested)
            {
                throw new Exception("error occured, and we're failing fast.");
            }
        }
예제 #21
0
        public static void Main(string[] args)
        {
            var configuration = GetConfiguration(args);

            try
            {
                var          prometheusConfig = configuration.GetSection("prometheusMetrics").Get <PrometheusConfig>();
                MetricServer metricServer     = null;
                if (prometheusConfig.Enabled)
                {
                    metricServer = new MetricServer(port: prometheusConfig.Port);
                    metricServer.Start();
                }

                CancellationTokenSource        cancellationTokenSource = new CancellationTokenSource();
                ProducerBuilder <Null, string> builder = new ProducerBuilder <Null, string>(configuration.GetSection("producerConf").Get <ProducerConfig>());
                builder.SetErrorHandler((_, error) =>
                {
                    Console.WriteLine($"An error ocurred producing the event: {error.Reason}");
                    if (error.IsFatal)
                    {
                        Environment.Exit(-1);
                    }
                });

                builder.HandleStatistics(new PrometheusProducerStatisticsHandler(new string[] { "application" }, new string[] { "test-producer-statistics" }));
                builder.SetKeySerializer(Serializers.Null);
                builder.SetValueSerializer(Serializers.Utf8);


                using (var producer = builder.Build())
                {
                    Action <DeliveryReport <Null, string> > handler = r =>
                    {
                        if (r.Error.IsError)
                        {
                            Console.WriteLine($"Delivery Error: {r.Error.Reason}");
                        }
                        else
                        {
                            Console.WriteLine($"Delivered message to {r.TopicPartitionOffset}");
                        }
                    };

                    int numMessages = 0;
                    while (!cancellationTokenSource.IsCancellationRequested)
                    {
                        try
                        {
                            var dr = producer.ProduceAsync(configuration.GetValue <string>("topic"), new Message <Null, string> {
                                Value = $"message {numMessages}"
                            });
                            Console.WriteLine($"Delivered  message {numMessages} : {dr.Result.Value}");
                            Thread.Sleep(1000);
                            numMessages++;
                        }
                        catch (ProduceException <Null, string> e)
                        {
                            Console.WriteLine($"Delivery failed: {e.Error.Reason}");
                        }
                    }

                    Console.WriteLine("Exit requested.");
                    producer.Flush(TimeSpan.FromSeconds(10));
                }

                Console.WriteLine("Exit requested. Gracefully exiting...");
            }
            catch (Exception ex)
            {
                Console.WriteLine("An error occurred while starting up the test.", ex);
                Environment.Exit(-2);
            }
        }
예제 #22
0
        private void DumpMessages <M>(IEnumerable <M> messages, Func <M, Message <K, T> > getMessage, CancellationToken cancellationToken)
        {
            var producerBuilder = new ProducerBuilder <K, T>(producerConfig);

            producerBuilder.SetKeySerializer(keySerializer);
            producerBuilder.SetValueSerializer(valueSerializer);
            producerBuilder.SetErrorHandler((_, e) => OnError?.Invoke(new StreamingError {
                IsFatal = e.IsFatal, Reason = e.Reason
            }));
            producerBuilder.SetStatisticsHandler((_, statistics) => OnStatistics?.Invoke(statistics));

            Stopwatch processTime = Stopwatch.StartNew();

            using (var p = producerBuilder.Build())
            {
                foreach (M message in messages)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    Policy.Handle <ProduceException <K, T> >()
                    .WaitAndRetryForever(retryAttempt => TimeSpan.FromMilliseconds(Math.Min(100 * Math.Pow(2, retryAttempt), 10000)),
                                         (exception, timespan) =>
                    {
                        var kafkaException = exception as ProduceException <K, T>;
                        OnError?.Invoke(new StreamingError
                        {
                            IsFatal = kafkaException.Error.IsFatal,
                            Reason  = $"{kafkaException.Error.Reason}. The message with key {kafkaException.DeliveryResult.Key} in topic {kafkaException.DeliveryResult.Topic} will be resent on {timespan.TotalMilliseconds} ms."
                        });
                    })
                    .Execute(() =>
                    {
                        if (!cancellationToken.IsCancellationRequested)
                        {
                            p.Produce(this.topic, getMessage.Invoke(message),
                                      r =>
                            {
                                if (r.Error.IsError)
                                {
                                    OnError?.Invoke(new StreamingError {
                                        IsFatal = r.Error.IsFatal, Reason = r.Error.Reason
                                    });
                                }
                            });
                        }
                    });

                    if (processTime.ElapsedMilliseconds >= CommitTimeoutMs)
                    {
                        p.Flush(cancellationToken);
                        if (!cancellationToken.IsCancellationRequested)
                        {
                            OnCommit?.Invoke();
                            processTime.Restart();
                        }
                    }
                }

                p.Flush(cancellationToken);

                if (!cancellationToken.IsCancellationRequested)
                {
                    OnCommit?.Invoke();
                }
            }
        }