我正在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,而没有输出或完成
由于Order
或iterator().hasNext()
中的偶发故障而发出警告。最终结果是整个管道都停滞了。相关的管道阶段从不发出输出。
使用标准的for循环替换循环即可解决此问题。但是,这样做意味着迭代整个集合。我宁愿在找到合适的元素后结束循环,因此是do-while循环。
我想知道为什么iterator().next()
操作会导致管道停顿。 FAIA iterator
集合是不可变的,不会被其他进程修改。
我正在 Windows 上运行 Java 8 和 Apache Beam 2.6 。
答案 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());
}
}