为什么可迭代操作会在Apache Beam函数中引发错误?

时间:2018-10-01 21:27:58

标签: java google-cloud-dataflow apache-beam google-cloud-pubsub

我正在Iterable函数的Java集合上调用此函数:

GroupByKey

该函数迭代static class FindCompleteOrder extends DoFn<KV<String, Iterable<Order>>, Order> { String COMPLETE_EVENT_NAME = "COMPLETE"; @ProcessElement public void processElement(ProcessContext c) { Iterable<Order> orders = c.element().getValue(); boolean complete = false; do { try { Order order = orders.iterator().next(); if (order.getEventName().equals(COMPLETE_EVENT_NAME)) { complete = true; order.setComplete(complete); c.output(order); } } catch (Exception e) { LOG.error(e.getMessage()); } } while (complete == false && orders.iterator().hasNext()); } } 的列表,并输出与指定的Orders属性匹配的第一个实例。如果找到eventName或整个集合已被迭代,则循环结束。

随机Order实例在上游生成,并以2 /秒的速率发布到 Pub / Sub 实例,并由 DataFlow消耗从中调用此函数的strong>实例。约手术15分钟后,警告开始出现:

  

处理停留在“查找订单”步骤中至少15m00,而没有输出或完成

由于Orderiterator().hasNext()中的偶发故障而发出警告。最终结果是整个管道都停滞了。相关的管道阶段从不发出输出。

使用标准的for循环替换循环即可解决此问题。但是,这样做意味着迭代整个集合。我宁愿在找到合适的元素后结束循环,因此是do-while循环。

我想知道为什么iterator().next()操作会导致管道停顿。 FAIA iterator集合是不可变的,不会被其他进程修改。

我正在 Windows 上运行 Java 8 Apache Beam 2.6

1 个答案:

答案 0 :(得分:1)

每次调用orders.iterator()时,都是从第一个顺序开始创建一个 new 迭代器。这意味着您将在循环中一遍又一遍地处理相同的订单。如果订单不止一个,那么您对hasNext()的呼叫将永远是正确的。因此,如果您有多个订单,或者您的第一个订单没有设置complete,则循环将永远运行,这就是为什么您超时的原因。

相反,您应该调用一次iterator()并存储迭代器而不是可迭代的,并使用它来循环:

static class FindCompleteOrder extends DoFn<KV<String, Iterable<Order>>, Order> {
    String COMPLETE_EVENT_NAME = "COMPLETE";

    @ProcessElement
    public void processElement(ProcessContext c) {
        Iterator<Order> orders = c.element().getValue().iterator();
        boolean complete = false;

        do {
            try {
                Order order = orders.next();

                if (order.getEventName().equals(COMPLETE_EVENT_NAME)) {
                    complete = true;
                    order.setComplete(complete);
                    c.output(order);
                }
            } catch (Exception e) {
                LOG.error(e.getMessage());
            }
        } while (complete == false && orders.hasNext());
    }
}