Java 为什么iterable操作会在Apache Beam函数中抛出错误?

Java 为什么iterable操作会在Apache Beam函数中抛出错误?,java,google-cloud-dataflow,apache-beam,google-cloud-pubsub,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(Process

我在一个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());
    }
}
该函数迭代订单列表,并输出与指定eventName属性匹配的第一个实例。如果找到顺序,或者迭代了整个集合,则循环结束

随机顺序实例在上游生成,并以2/秒的速率发布到发布/订阅实例,在那里它们由调用此函数的数据流实例使用。操作大约15分钟后,警告开始出现:

在没有输出或完成的情况下,处理卡在步骤查找顺序中至少15m00秒

由于iterator.hasNext或iterator.next中的偶发故障而发出警告。最终结果是整个管道暂停。关联的管道级从不发出输出

用标准for loop替换loop解决了这个问题。然而,这样做意味着迭代整个集合;我更愿意在找到合适的元素时结束循环,因此执行do while循环

我很想知道迭代器操作为什么会导致管道暂停。FAIA Iterable集合是不可变的,并且没有被其他进程修改

我在Windows上运行Java 8和Apache Beam 2.6。

每次调用orders.iterator时,您都在创建一个新的迭代器,从第一个order开始。这意味着您在循环中一次又一次地处理相同的订单。如果有多个订单,您对hasNext的调用将始终为真。因此,如果您有多个订单,或者您的第一个订单没有设置完成,那么循环将永远运行,这就是您遇到超时的原因

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

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());
    }
}