I have java application with using Spring-Data. I need to use a resumeToken for cases where an exception will occur when the change stream listener is running. Now I'm simulating the occurrence of an exception manually.
When I try to simulate an exception and throw it from userListener() method, it gets into the createListener() method catch block, but it doesn't get into the register() method catch block, where I could apply it.
Method with listener functionality. This is where I'm throwing the exception manually for my test:
private MessageListener<ChangeStreamDocument<Document>, User> userListener() throws Exception {
return createListener(new CallbackChangeStream<User>() {
@Override
public void insert(ChangeStreamDocument<Document> raw, User body) {
log.info("new user is inserted, content is {}.", body.toString());
throw new MongoCommandException(raw.getResumeToken(), new ServerAddress());
}
});
}
The method from where the mongo change stream event listener is called depending on the operation type. The exception is caught in the catch block of this method:
private <T> MessageListener<ChangeStreamDocument<Document>, T> createListener(CallbackChangeStream<T> callback) {
return listenMsg -> {
ChangeStreamDocument<Document> raw = listenMsg.getRaw();
OperationType operationType = Objects.requireNonNull(raw).getOperationType();
try {
switch (operationType) {
case INSERT: callback.insert(raw, listenMsg.getBody());
default: break;
}
} catch (MongoCommandException e) {
throw e;
}
};
}
public interface CallbackChangeStream<T> {
void insert(ChangeStreamDocument<Document> raw, T body);
}
Methods where I can apply resumeToken in case the catch block is triggered. But the exception is not being caught here:
private <T> void registerListener(
String collectionName,
MessageListener<ChangeStreamDocument<Document>, T> listener,
Class<T> bodyType,
Optional<BsonDocument> resumeToken
) {
ChangeStreamOptions.ChangeStreamOptionsBuilder builder = ChangeStreamOptions.builder().returnFullDocumentOnUpdate();
if (resumeToken.isPresent()) {
builder.resumeToken(resumeToken.get());
}
registerListener(collectionName, listener, bodyType, builder.build());
}
public void register(BsonDocument token) {
boolean ignoreLastResumeToken = false;
do {
try {
registerListener("user", userListener(), User.class, token);
ignoreLastResumeToken = false;
} catch (MongoCommandException e) {
ignoreLastResumeToken = true;
}
} while (ignoreLastResumeToken);
}
My imports:
import org.bson.Document
import com.mongodb.client.model.changestream.ChangeStreamDocument
import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.messaging.MessageListener
My exception stackTrace:
Exception in thread "SimpleAsyncTaskExecutor-1" com.mongodb.MongoCommandException: Command failed with error -1: '' on server 127.0.0.1:27017. The full response is { "_data" : "82631AABD60000001F2B022C0100296E5A1004A257E76C43E64F0DA263D1282932AA1046645F696400646313BE07AD57A0ECFE5FBBBD0004" }
at com.demo.web.ChangeStreamListener$1.update(ChangeStreamListener.java:85)
at com.demo.web.ChangeStreamListener$1.update(ChangeStreamListener.java:74)
at com.demo.web.ChangeStreamListener.lambda$createMessageListener$0(ChangeStreamListener.java:144)
at org.springframework.data.mongodb.core.messaging.CursorReadingTask.emitMessage(CursorReadingTask.java:222)
at org.springframework.data.mongodb.core.messaging.CursorReadingTask.run(CursorReadingTask.java:85)
at java.base/java.lang.Thread.run(Thread.java:833)
How can I catch the exception in order to use the resumeToken ?