获取返回Mono.empty()的Mono/Flux的行号



假设我有一长串Monos。链中的一些单体可能返回CCD_ 1。

我可以用switchIfEmpty恢复,但我想知道是哪个单声道引发了空(也许这样我就可以知道在哪里添加更智能的空处理(。

有没有一种方法可以通过编程获得这些信息?

愚蠢的例子。在返回how did I get here?的情况下,如何知道第一个flatMap还是第二个flatMap触发了空处理程序?

Mono.just("data")
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0) {
return Mono.empty();
}
return Mono.just("happy1");
})
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0) {
return Mono.empty();
}
return Mono.just("happy2");
})
.map(s -> {
return "successful complete: " + s;
})
.switchIfEmpty(Mono.fromCallable(() -> {
return "how did I get here?";
}))
.block();

由于FluxMono的动态特性,以及onComplete信号被认为是中性的,通常只是通过,因此没有通用的解决方案。

在您的特定示例中,您可以将Mono.empty()替换为类似Mono.empty()0的内容。您甚至可以直接在if块中执行日志记录,但修饰的空技巧可能适用于更多情况。

另一种可能性是将空变为错误,而不是打开onComplete信号。错误不那么中性,因此有一些方法可以丰富它们以进行调试。例如,在每个flatMap之后使用.checkpoint("flatMapX")语句,您将获得额外的堆栈跟踪部分,这些部分将指向由于空而失败的flatMap。

Mono中将空变为错误的一种方法是.single(),它将强制执行一个onNext()或传播onError(NoSuchElementException)

这个技巧需要记住的一点是checkpoint的位置很重要:它必须在single()之后,这样才能检测到并丰富从single((引发的错误。

所以,如果我建立在你的代码片段上:

static final String PARSEABLE_MARKER = "PARSEABLE MARKER: <";
static final char MARKER_END = '>';
String parseLocation(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String trace = sw.toString();
int start = trace.indexOf(PARSEABLE_MARKER);
if (start > 0) {
trace = trace.substring(start + PARSEABLE_MARKER.length());
trace = trace.substring(0, trace.indexOf(MARKER_END));
return trace;
}
return "I don't know";
}
String testInner() {
Random random = new Random();
final boolean first = random.nextBoolean();
return Mono.just("data")
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0 && first) {
return Mono.empty();
}
return Mono.just("happy1");
})
.single()
.checkpoint(PARSEABLE_MARKER + "the first flatMap" + MARKER_END)
.flatMap(t -> {
if (System.currentTimeMillis() % 2 == 0 && !first) {
return Mono.empty();
}
return Mono.just("happy2");
})
.single()
.checkpoint(PARSEABLE_MARKER + "the second flatMap" + MARKER_END)
.map(s -> {
return "successful complete: " + s;
})
.onErrorResume(NoSuchElementException.class, e ->
Mono.just("how did I get here? " + parseLocation(e)))
.block();
}

这可以在测试中循环运行,例如:

@Test
void test() {
int successCount = 0;
int firstCount = 0;
int secondCount = 0;
for (int i = 0; i < 100; i++) {
String message = testInner();
if (message.startsWith("how")) {
if (message.contains("first")) {
firstCount++;
}
else if (message.contains("second")) {
secondCount++;
}
else {
System.out.println(message);
}
}
else {
successCount++;
}
}
System.out.printf("Stats: %d successful, %d detected first, %d detected second", successCount, firstCount, secondCount);
}

它打印的东西像:

Stats: 85 successful, 5 detected first, 10 detected second

最新更新