Java 如何将轮询api转换为反应流

Java 如何将轮询api转换为反应流,java,project-reactor,Java,Project Reactor,假设我有一个具有以下签名的函数: class Item { String name; Long id; } public Flux<Item> getNew(long id); 我能做到这一点的唯一方法是使用某种类型的状态变量: public Flux<Long> observe(long id) { final AtomicLong last = new AtomicLong(id); return Flux.interval(Dur

假设我有一个具有以下签名的函数:

class Item {
  String name;
  Long id;
}
public Flux<Item> getNew(long id);
我能做到这一点的唯一方法是使用某种类型的状态变量:

   public Flux<Long> observe(long id) {
     final AtomicLong last = new AtomicLong(id);
     return Flux.interval(Duration.ofSeconds(1)).
         flatMap(l -> getNew(last.get())).
         doOnNext(last::set);    
   }    
公共流量观测(长id){
最终原子长度last=新原子长度(id);
返回通量间隔(持续时间秒(1))。
flatMap(l->getNew(last.get()))。
doOnNext(最后一个::集);
}    

有没有更惯用的方法?我试图为它创建生成器,但我不知道如何实现它

如果可以通过检查来识别由
getNew
发出的最后一个
项目,则可以使用运算符:

公共流量观测(长id){
返回getNew(id)
.展开(项目->isLast(项目)
?getNew(项目id)
:Flux.empty());
}
/**
*@如果给定项是getNew发出的最后一项,则返回true
*/
私有布尔isLast(项){
返回//…剪断。。。
}
如果无法通过检查来识别最后一个
,则必须使用状态变量。尽管如此,我还是建议使用and而不是
.interval

公共流量观测(长id){
最终原子长nextStartId=新原子长(id);
return Flux.defer(()->getNew(nextStartId.get())
.doOnNext(项目->下一个开始id.set(项目id))
.重复();
}
反对使用的主要原因是:

如果未及时生成需求,将发出一个onError信号

因此,如果API花费的时间太长,或者处理结果花费的时间太长,则流将以错误结束。对于较长的间隔,这可能不是问题,但是对于相对较短的间隔(例如示例中的1秒),这可能是问题


如果您想在每次重复迭代之前延迟,那么可以使用
.repeatWhen
,使用带有固定回退的reactor extra。这将为您提供“固定延迟”语义,而不是“固定间隔”。

如果您可以通过检查来识别由
getNew
发出的最后一个
项,则可以使用以下运算符:

公共流量观测(长id){
返回getNew(id)
.展开(项目->isLast(项目)
?getNew(项目id)
:Flux.empty());
}
/**
*@如果给定项是getNew发出的最后一项,则返回true
*/
私有布尔isLast(项){
返回//…剪断。。。
}
如果无法通过检查来识别最后一个
,则必须使用状态变量。尽管如此,我还是建议使用and而不是
.interval

公共流量观测(长id){
最终原子长nextStartId=新原子长(id);
return Flux.defer(()->getNew(nextStartId.get())
.doOnNext(项目->下一个开始id.set(项目id))
.重复();
}
反对使用的主要原因是:

如果未及时生成需求,将发出一个onError信号

因此,如果API花费的时间太长,或者处理结果花费的时间太长,则流将以错误结束。对于较长的间隔,这可能不是问题,但是对于相对较短的间隔(例如示例中的1秒),这可能是问题


如果您想在每次重复迭代之前延迟,那么可以使用
.repeatWhen
,使用带有固定回退的reactor extra。这将为您提供“固定延迟”语义,而不是“固定间隔”。

我只能通过该项是流中的最后一项这一事实来识别该项。使用“延迟/重复”有什么好处?请注意,getNew正在轮询,我需要定期调用它。更新的答案包含了使用
的缺点。interval
这对好奇的人来说是一个退避。我只能通过它是流中最后一个的事实来识别该项。使用“延迟/重复”有什么好处?请注意,getNew正在进行轮询,我需要定期调用它。更新的答案包括使用
的缺点。interval
这对好奇的人来说有退避的余地。
   public Flux<Long> observe(long id) {
     final AtomicLong last = new AtomicLong(id);
     return Flux.interval(Duration.ofSeconds(1)).
         flatMap(l -> getNew(last.get())).
         doOnNext(last::set);    
   }