Exception 如果拓扑中发生异常,则跳过记录

Exception 如果拓扑中发生异常,则跳过记录,exception,apache-kafka,apache-kafka-streams,Exception,Apache Kafka,Apache Kafka Streams,我们正在编写一个Kafka Streams拓扑,用于聚合数据并实时显示它们。我们希望使显示尽可能稳定-理想情况下记录记录并继续进行任何异常 根据文件,我们和 Kafka Streams非常支持处理在生产者中或反序列化期间发生的异常。提供的LogAndContinueExceptionHandler准确地给出了我们想要的行为。但是,我们的主要问题是在处理过程中发生的异常(例如.mapValues()或.leftJoin() 我们的想法基本上是验证先决条件 在反序列化期间,如果未实现,则引

我们正在编写一个Kafka Streams拓扑,用于聚合数据并实时显示它们。我们希望使显示尽可能稳定-理想情况下记录记录并继续进行任何异常

根据文件,我们和

Kafka Streams非常支持处理在生产者中或反序列化期间发生的异常。提供的
LogAndContinueExceptionHandler
准确地给出了我们想要的行为。但是,我们的主要问题是在处理过程中发生的异常(例如
.mapValues()
.leftJoin()

我们的想法基本上是验证先决条件

  • 在反序列化期间,如果未实现,则引发反序列化异常(并记录并继续)
  • As在处理函数中进行检查,以在无法执行计算时返回默认值(
    /by zero error
    等)
  • 但是,如果数据中存在不可预见的情况,异常仍可能出现,拓扑将关闭

    Kafka Streams提供了一个
    UncaughtExceptionHandler
    ,但它是在线程已经死亡后调用的,因此不能用于防止拓扑关闭


    是否有某种方法可以编写一个跳过记录的UncaughtExceptionHandler?或者有一种机制可以跳过当前记录,我们可以在处理函数中的
    try catch
    块中使用这种机制?

    我认为最好的解决方案是编写处理操作(例如:映射器、过滤器等)这样,您就不会抛出任何异常。为此,您可以使用一个包装器对象,该对象可以是成功的,也可以是错误的(例如:scala中的
    类型)。然后,您可以使用
    分支()
    方法获取两个流:一个用于成功记录,另一个用于错误

    下面的代码显示了基本思想:

        public static void main(String[] args) {
            var builder = new StreamsBuilder();
            KStream<Object, Result<Object>> stream = builder.stream("my-topic")
                .map((k, v) -> {
                    try {
                        // unsafe operation, i.e that may throw an exception
                        return KeyValue.pair(k, new Success<>(v));
                    } catch (Exception e) {
                        return KeyValue.pair(k, new Error<>(e));
                    }
                });
            KStream<Object, Result<Object>>[] branch = stream.branch((k, v) -> !v.hasError(), (k, v) -> v.hasError());
    
            // Handle the success steam
            KStream<Object, Result<Object>> successStream = branch[0];
    
            // Handle the error steam, e.g:  log errors, write errors to a Dead Letter Queue
            KStream<Object, Result<Object>> errorStream = branch[1];
            
        }
    
        public interface Result<T> {
            T get() throws Exception;
            Exception exception();
            boolean hasError();
        }
    
        public static class Success<T> implements Result<T> {
    
            private final T value;
    
            public Success(T value) {
                this.value = value;
            }
    
            @Override
            public T get() throws Exception {
                return value;
            }
    
            @Override
            public Exception exception() {
                return null;
            }
    
            @Override
            public boolean hasError() {
                return false;
            }
        }
    
        public static class Error<T> implements Result<T> {
    
            private final Exception error;
    
            public Error(Exception error) {  this.error = error; }
    
            @Override
            public T get() throws Exception{
                throw error;
            }
    
            @Override
            public Exception exception() {
                return error;
            }
    
            @Override
            public boolean hasError() {
                return true;
            }
        }
    
    publicstaticvoidmain(字符串[]args){
    var builder=new StreamsBuilder();
    KStream stream=builder.stream(“我的主题”)
    .map((k,v)->{
    试一试{
    //不安全操作,即可能引发异常
    返回KeyValue.pair(k,新成功(v));
    }捕获(例外e){
    返回KeyValue.pair(k,新错误(e));
    }
    });
    KStream[]branch=stream.branch((k,v)->!v.hasError(),(k,v)->v.hasError());
    //把握成功的动力
    KStream successStream=分支[0];
    //处理错误流,例如:记录错误、将错误写入死信队列
    KStream errorStream=分支[1];
    }
    公共接口结果{
    T get()抛出异常;
    异常异常();
    布尔hasrerror();
    }
    公共静态类成功实现结果{
    私人最终T值;
    公众成功(T值){
    这个值=值;
    }
    @凌驾
    public T get()引发异常{
    返回值;
    }
    @凌驾
    公共例外(){
    返回null;
    }
    @凌驾
    公共布尔hasError(){
    返回false;
    }
    }
    公共静态类错误实现结果{
    私有最终异常错误;
    公共错误(异常错误){this.Error=Error;}
    @凌驾
    public T get()引发异常{
    投掷误差;
    }
    @凌驾
    公共例外(){
    返回误差;
    }
    @凌驾
    公共布尔hasError(){
    返回true;
    }
    }
    

    此外,对于您提到的反序列化异常,项目提供了一些方便的java类,可以帮助您(例如SafeSerdes、DeadLetterTopiceExceptionHandler):