我有一个群集中有多个节点的应用程序。每个节点将日志文件写入其本地磁盘。我已经实现了一个日志搜索功能,可以在每个节点上搜索日志。从浏览器接收搜索请求的所有者节点将日志搜索作业提交给其他节点,然后其他节点将搜索结果传递给原始节点。客户端Web浏览器使用长轮询来从节点获取搜索结果。这似乎非常适合RxJava,因为每个节点都是一个事件流,客户端从所有节点获取一个统一的事件流。 (我们假设一个吝啬的运营团队不会让我们使用Splunk或其他一些商业日志记录解决方案。)
客户端轮询原始节点上的REST API,该API收集搜索结果。我对REST API的理想逻辑如下:
我编写了以下示例代码来模拟这种情况:
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(5);
/* Each searchTask represents the results of a search job running on a
* node in the cluster */
Subject<String,String> searchTask1 = PublishSubject.create();
Subject<String,String> searchTask2 = PublishSubject.create();
// Limit max number of search results
Observable<String> searchResults =
Observable.merge(searchTask1, searchTask2).take( 1000 );
/* Add a 100ms buffer window to collect nearby responses together.
* Filter out any empty buffers to eliminate unnecessary
* responses to the browser. */
BlockingObservable<List<String>> blocking =
searchResults.buffer(100, TimeUnit.MILLISECONDS)
.filter(results -> !results.isEmpty()).toBlocking();
Iterator<List<String>> it = blocking.getIterator();
/* Each call to searchTask.onNext represents a search result pushed
* to the owner node from another node. This code would be called
* from the REST endpoint. */
executorService.submit( () -> {
searchTask1.onNext("1");
try { Thread.sleep(1200); } catch ( Exception ignored ) { }
searchTask1.onNext("2");
searchTask1.onCompleted();
});
executorService.submit( () -> {
searchTask2.onNext("a");
try { Thread.sleep(500); } catch ( Exception ignored ) { }
searchTask2.onNext("b");
searchTask2.onCompleted();
});
executorService.submit( () -> {
/* Each iteration of this loop represents a polling request from
* the browser and the results that are sent back to it. */
for ( int i = 0; i < 5; i++ ) {
it.forEachRemaining(results -> System.out.println(results));
}
});
Thread.sleep(1500);
System.out.println("exit");
}
for循环中的逻辑应该确保在最多15秒后始终将响应发送回客户端(即使响应为空)?
编辑:我用更多评论更新了示例代码,并显示了我当前的解决方案,但我仍然无法获得15秒的最大响应时间。我们的网络设备将关闭空闲时间过长的HTTP连接,因此我想保证客户端在最多15秒后始终得到响应。
答案 0 :(得分:0)
我能找到的所有RxJava文章似乎都非常关注客户端代码而不是服务器端代码。然而,在与Observable运算符争论了一下之后,我想出了以下解决方案接近我想要的。心跳发生在每15秒而不是前一次结果后15秒。这意味着服务器可能在发送结果后立即向客户端发送心跳响应,但这对我来说足够接近。
我创建了一个15秒的间隔可观察对象,并将其与我已经拥有的searchResults
可观察对象合并。我使用了一个主题,这样当结果流停止时我可以停止可观察的间隔(否则它会无限期地继续)。
/* Add a heartbeat that ensures we don't wait too long between
* sending responses and some network device kills our connection */
final Observable<String> heartbeat =
Observable.interval( 1, TimeUnit.SECONDS ).map(el -> "heartbeat");
final PublishSubject<String> stopHeartbeat = PublishSubject.create();
searchResults.subscribe( el -> {}, ex -> {}, () -> stopHeartbeat.onNext( null ) );
final Observable<String> searchResultsWithHeartbeat =
searchResults.mergeWith( heartbeat.takeUntil( stopHeartbeat ) );