Subscription query with initial result not found

Hi all,

I have a question about handling the Not Found scenario in subscription queries. There are a couple of way in which I use subscription queries and this issue is only related to one of the scenarios. The scenario is where a user in the application subscribes to a specific model instance in order to monitor it. As the instance changes in the system, the updates are emitted through the subscription channel and the UI magically updates–which is really great stuff! The issue comes in when a user provides invalid information to the subscription and the query for the initial result raises a NoSuchElementException however this exception is consumed by the subscription query machinery and I can’t seem to respond to it.

I’ve tried the following but I can’t get an exception:

SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult = subscribeToPackageRecord(id); return queryResult.initialResult().mergeWith(queryResult.updates()).doOnError(e -> { throw new RuntimeException(e); });

Without an exception here, the client doesn’t know that the request was invalid and that the subscription stream will never get an update (or even have an initial result). What I’d really like this to do is to simply propagate the NoSuchElementException from the QueryHandler through REST controller method the subscription query code above was clipped from.

Cheers,

Troy

I have also tried a slightly different variant:

`

SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult = subscribeToPackageRecord(id);
return queryResult.initialResult().doOnError(e -> {
throw new RuntimeException(e);
}).mergeWith(queryResult.updates());

`

But it doesn’t seem to matter. In either case I get the following in the logs:

`

e[2m2018-11-19 16:38:12.159e[0;39m e[31mERROR [-,]e[0;39m e[35m3228e[0;39m e[2m—e[0;39m e[2m[ault-executor-0]e[0;39m e[36mo.a.queryhandling.SimpleQueryBus e[0;39m e[2m:e[0;39m An error happened while trying to report an initial result. Query: org.axonframework.axonserver.connector.query.subscription.GrpcBackedSubscriptionQueryMessage@18415140

java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at com.fedexx.pkg.query.PackageRecordProjector.handle(PackageRecordProjector.java:189)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.axonframework.messaging.annotation.AnnotatedMessageHandlingMember.handle(AnnotatedMessageHandlingMember.java:127)
at org.axonframework.messaging.annotation.WrappedMessageHandlingMember.handle(WrappedMessageHandlingMember.java:61)
at org.axonframework.queryhandling.annotation.AnnotationQueryHandlerAdapter.handle(AnnotationQueryHandlerAdapter.java:95)
at org.axonframework.queryhandling.annotation.AnnotationQueryHandlerAdapter.handle(AnnotationQueryHandlerAdapter.java:36)
at org.axonframework.messaging.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:57)
at org.axonframework.messaging.interceptors.CorrelationDataInterceptor.handle(CorrelationDataInterceptor.java:65)
at org.axonframework.messaging.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:55)
at org.axonframework.queryhandling.SimpleQueryBus.lambda$interceptAndInvoke$9(SimpleQueryBus.java:266)
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.executeWithResult(DefaultUnitOfWork.java:74)
at org.axonframework.messaging.unitofwork.UnitOfWork.executeWithResult(UnitOfWork.java:328)
at org.axonframework.queryhandling.SimpleQueryBus.interceptAndInvoke(SimpleQueryBus.java:264)
at org.axonframework.queryhandling.SimpleQueryBus.query(SimpleQueryBus.java:154)
at org.axonframework.queryhandling.SimpleQueryBus.lambda$subscriptionQuery$6(SimpleQueryBus.java:228)
at org.axonframework.queryhandling.MonoWrapper.lambda$create$0(MonoWrapper.java:62)
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:54)
at reactor.core.publisher.MonoLift.subscribe(MonoLift.java:46)
at reactor.core.publisher.Mono.subscribe(Mono.java:3080)
at reactor.core.publisher.Mono.subscribeWith(Mono.java:3188)
at reactor.core.publisher.Mono.subscribe(Mono.java:3074)
at reactor.core.publisher.Mono.subscribe(Mono.java:3041)
at reactor.core.publisher.Mono.subscribe(Mono.java:3013)
at org.axonframework.axonserver.connector.query.subscription.SubscriptionQueryRequestTarget.getInitialResult(SubscriptionQueryRequestTarget.java:99)
at org.axonframework.axonserver.connector.query.subscription.SubscriptionQueryRequestTarget.onSubscriptionQueryRequest(SubscriptionQueryRequestTarget.java:70)
at org.axonframework.axonserver.connector.query.AxonServerQueryBus$QueryProvider$1.lambda$onNext$0(AxonServerQueryBus.java:369)
at java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:891)
at java.util.concurrent.CopyOnWriteArraySet.forEach(CopyOnWriteArraySet.java:404)
at org.axonframework.axonserver.connector.query.AxonServerQueryBus$QueryProvider$1.onNext(AxonServerQueryBus.java:369)
at org.axonframework.axonserver.connector.query.AxonServerQueryBus$QueryProvider$1.onNext(AxonServerQueryBus.java:364)
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onMessage(ClientCalls.java:407)
at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:519)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

`

Also, here’s what the client sees when the request is valid:

`

troyh@piehole:~/fx/repos/recover (pi2.4 *%=)$ curl -v --request GET --url http://recover-api:8081/packages/a6026414-798e-41f4-80e0-4edee5ba57b0 --header ‘authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVcElUaXNJQnIxck1TblVpV0RZdGptZXJ2cmluQUNiN3dKU29lME15REpNIn0.eyJqdGkiOiJjMjc5ODg4Mi1lOTM4LTQ5MDItODNlOS04NWYzYmY5MzcyNTMiLCJleHAiOjE1NDI2OTA0OTIsIm5iZiI6MCwiaWF0IjoxNTQyNjU0NDk0LCJpc3MiOiJodHRwOi8vcmVjb3Zlci1zc286ODI4MC9hdXRoL3JlYWxtcy9yZWNvdmVyIiwiYXVkIjoicmVjb3Zlci1hcHAiLCJzdWIiOiJkODAwNTIyMy04MjFmLTRiMjktYTYyZC03NDMwN2EzMmU0ZTciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJyZWNvdmVyLWFwcCIsIm5vbmNlIjoiM2E4MTMzYjAtOGU0MS00YjU4LThmNTYtZmJkY2U3OWEzNDU5IiwiYXV0aF90aW1lIjoxNTQyNjU0NDkyLCJzZXNzaW9uX3N0YXRlIjoiODYxMGQyMjYtMjNlZC00YzMwLTk4MjEtNjZlY2IzNjI2ZDBlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vZG9ja2VyLmc0LnFhLmxhbjo4MDgyIiwiaHR0cDovL3JlY292ZXItd2ViOjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiVHJveSBIYXJ0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHJveWgiLCJnaXZlbl9uYW1lIjoiVHJveSIsImZhbWlseV9uYW1lIjoiSGFydCIsImVtYWlsIjoidHJveS5oYXJ0QGdtYWlsLmNvbSJ9.UgSzZbMlBYiTTz6SCHDdQ4B4BnHcOTSznORBcdu54NTvkZipLVx3SKt7M1BaqNNpMkTA6pqnFb-wSwJ-9mTrkQqPR9c–HoXidilwRgWLzemeLI65vNY9VTEb4xk6TUm2sRlT7-CTRZNuSogtvPtqkfUZsLkc1IQO_3BRdTufV_07u48uBwpBIdz-sriZwdYox4zTP4gQmaUqbNlcsw39BUt3bvWT3Pk1Yvcxg_4mRr4Yi1aVY0tsa3VqCCycl-XjB0EQ3Nzf5cg6dyCjU-KIM81qgmdoiiVEO5hlmOZpoBoC7tvqGh_eQpcbonYXoBwVQKtWzLzz3C5bvh4aug55Q’
Note: Unnecessary use of -X or --request, GET is already inferred.

  • Trying 127.0.0.1…
  • Connected to recover-api (127.0.0.1) port 8081 (#0)

GET /packages/a6026414-798e-41f4-80e0-4edee5ba57b0 HTTP/1.1
Host: recover-api:8081
User-Agent: curl/7.47.0
Accept: /
authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVcElUaXNJQnIxck1TblVpV0RZdGptZXJ2cmluQUNiN3dKU29lME15REpNIn0.eyJqdGkiOiJjMjc5ODg4Mi1lOTM4LTQ5MDItODNlOS04NWYzYmY5MzcyNTMiLCJleHAiOjE1NDI2OTA0OTIsIm5iZiI6MCwiaWF0IjoxNTQyNjU0NDk0LCJpc3MiOiJodHRwOi8vcmVjb3Zlci1zc286ODI4MC9hdXRoL3JlYWxtcy9yZWNvdmVyIiwiYXVkIjoicmVjb3Zlci1hcHAiLCJzdWIiOiJkODAwNTIyMy04MjFmLTRiMjktYTYyZC03NDMwN2EzMmU0ZTciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJyZWNvdmVyLWFwcCIsIm5vbmNlIjoiM2E4MTMzYjAtOGU0MS00YjU4LThmNTYtZmJkY2U3OWEzNDU5IiwiYXV0aF90aW1lIjoxNTQyNjU0NDkyLCJzZXNzaW9uX3N0YXRlIjoiODYxMGQyMjYtMjNlZC00YzMwLTk4MjEtNjZlY2IzNjI2ZDBlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vZG9ja2VyLmc0LnFhLmxhbjo4MDgyIiwiaHR0cDovL3JlY292ZXItd2ViOjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiVHJveSBIYXJ0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHJveWgiLCJnaXZlbl9uYW1lIjoiVHJveSIsImZhbWlseV9uYW1lIjoiSGFydCIsImVtYWlsIjoidHJveS5oYXJ0QGdtYWlsLmNvbSJ9.UgSzZbMlBYiTTz6SCHDdQ4B4BnHcOTSznORBcdu54NTvkZipLVx3SKt7M1BaqNNpMkTA6pqnFb-wSwJ-9mTrkQqPR9c–HoXidilwRgWLzemeLI65vNY9VTEb4xk6TUm2sRlT7-CTRZNuSogtvPtqkfUZsLkc1IQO_3BRdTufV_07u48uBwpBIdz-sriZwdYox4zTP4gQmaUqbNlcsw39BUt3bvWT3Pk1Yvcxg_4mRr4Yi1aVY0tsa3VqCCycl-XjB0EQ3Nzf5cg6dyCjU-KIM81qgmdoiiVEO5hlmOZpoBoC7tvqGh_eQpcbonYXoBwVQKtWzLzz3C5bvh4aug55Q

< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/event-stream;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Mon, 19 Nov 2018 23:46:19 GMT
<
data:{“packageId”:“a6026414-798e-41f4-80e0-4edee5ba57b0”,“inventoryItemId”:“PKG-20181119-007502039”,“aggregateVersion”:1,“opCo”:“GROUND”,“weightDim”:{“weight”:38.0,“unitsWeight”:“LBS”,“length”:7.0,“width”:14.0,“height”:12.0,“unitsDim”:“IN”},“originInfo”:{“discoveryFacilityId”:“JDYK”,“originalTrackingNumber”:null,“originalMPSParentTrackingNumber”:null,“transferTrackingNumbers”:[“123456798012”]},“packageType”:“OVERGOOD”,“issueType”:“OVERGOOD_WITH_PACKAGING”,“contributingCauses”:[“LABEL_BELT_BURN”,“TRACKING_NUMBER_REMOVED”],“packaging”:{“attributeValues”:{“PACKAGING_TYPE”:[“BAG_LG_POLY”]},“flags”:[]},“contents”:[],“createdBy”:“AGENT”,“createdInstant”:1542667760.882000000,“lastModifiedBy”:“SYSTEM”,“lastModifiedInstant”:1542667765.064000000,“contentCount”:0}

`

And this is what the client seems when the request does properly identify the model:

`

troyh@piehole:~/fx/repos/recover (pi2.4 *%=)$ curl -v --request GET --url http://recover-api:8081/packages/xa6026414-798e-41f4-80e0-4edee5ba57b0 --header ‘authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVcElUaXNJQnIxck1TblVpV0RZdGptZXJ2cmluQUNiN3dKU29lME15REpNIn0.eyJqdGkiOiJjMjc5ODg4Mi1lOTM4LTQ5MDItODNlOS04NWYzYmY5MzcyNTMiLCJleHAiOjE1NDI2OTA0OTIsIm5iZiI6MCwiaWF0IjoxNTQyNjU0NDk0LCJpc3MiOiJodHRwOi8vcmVjb3Zlci1zc286ODI4MC9hdXRoL3JlYWxtcy9yZWNvdmVyIiwiYXVkIjoicmVjb3Zlci1hcHAiLCJzdWIiOiJkODAwNTIyMy04MjFmLTRiMjktYTYyZC03NDMwN2EzMmU0ZTciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJyZWNvdmVyLWFwcCIsIm5vbmNlIjoiM2E4MTMzYjAtOGU0MS00YjU4LThmNTYtZmJkY2U3OWEzNDU5IiwiYXV0aF90aW1lIjoxNTQyNjU0NDkyLCJzZXNzaW9uX3N0YXRlIjoiODYxMGQyMjYtMjNlZC00YzMwLTk4MjEtNjZlY2IzNjI2ZDBlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vZG9ja2VyLmc0LnFhLmxhbjo4MDgyIiwiaHR0cDovL3JlY292ZXItd2ViOjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiVHJveSBIYXJ0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHJveWgiLCJnaXZlbl9uYW1lIjoiVHJveSIsImZhbWlseV9uYW1lIjoiSGFydCIsImVtYWlsIjoidHJveS5oYXJ0QGdtYWlsLmNvbSJ9.UgSzZbMlBYiTTz6SCHDdQ4B4BnHcOTSznORBcdu54NTvkZipLVx3SKt7M1BaqNNpMkTA6pqnFb-wSwJ-9mTrkQqPR9c–HoXidilwRgWLzemeLI65vNY9VTEb4xk6TUm2sRlT7-CTRZNuSogtvPtqkfUZsLkc1IQO_3BRdTufV_07u48uBwpBIdz-sriZwdYox4zTP4gQmaUqbNlcsw39BUt3bvWT3Pk1Yvcxg_4mRr4Yi1aVY0tsa3VqCCycl-XjB0EQ3Nzf5cg6dyCjU-KIM81qgmdoiiVEO5hlmOZpoBoC7tvqGh_eQpcbonYXoBwVQKtWzLzz3C5bvh4aug55Q’
Note: Unnecessary use of -X or --request, GET is already inferred.

  • Trying 127.0.0.1…
  • Connected to recover-api (127.0.0.1) port 8081 (#0)

GET /packages/xa6026414-798e-41f4-80e0-4edee5ba57b0 HTTP/1.1
Host: recover-api:8081
User-Agent: curl/7.47.0
Accept: /
authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVcElUaXNJQnIxck1TblVpV0RZdGptZXJ2cmluQUNiN3dKU29lME15REpNIn0.eyJqdGkiOiJjMjc5ODg4Mi1lOTM4LTQ5MDItODNlOS04NWYzYmY5MzcyNTMiLCJleHAiOjE1NDI2OTA0OTIsIm5iZiI6MCwiaWF0IjoxNTQyNjU0NDk0LCJpc3MiOiJodHRwOi8vcmVjb3Zlci1zc286ODI4MC9hdXRoL3JlYWxtcy9yZWNvdmVyIiwiYXVkIjoicmVjb3Zlci1hcHAiLCJzdWIiOiJkODAwNTIyMy04MjFmLTRiMjktYTYyZC03NDMwN2EzMmU0ZTciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJyZWNvdmVyLWFwcCIsIm5vbmNlIjoiM2E4MTMzYjAtOGU0MS00YjU4LThmNTYtZmJkY2U3OWEzNDU5IiwiYXV0aF90aW1lIjoxNTQyNjU0NDkyLCJzZXNzaW9uX3N0YXRlIjoiODYxMGQyMjYtMjNlZC00YzMwLTk4MjEtNjZlY2IzNjI2ZDBlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vZG9ja2VyLmc0LnFhLmxhbjo4MDgyIiwiaHR0cDovL3JlY292ZXItd2ViOjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiVHJveSBIYXJ0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHJveWgiLCJnaXZlbl9uYW1lIjoiVHJveSIsImZhbWlseV9uYW1lIjoiSGFydCIsImVtYWlsIjoidHJveS5oYXJ0QGdtYWlsLmNvbSJ9.UgSzZbMlBYiTTz6SCHDdQ4B4BnHcOTSznORBcdu54NTvkZipLVx3SKt7M1BaqNNpMkTA6pqnFb-wSwJ-9mTrkQqPR9c–HoXidilwRgWLzemeLI65vNY9VTEb4xk6TUm2sRlT7-CTRZNuSogtvPtqkfUZsLkc1IQO_3BRdTufV_07u48uBwpBIdz-sriZwdYox4zTP4gQmaUqbNlcsw39BUt3bvWT3Pk1Yvcxg_4mRr4Yi1aVY0tsa3VqCCycl-XjB0EQ3Nzf5cg6dyCjU-KIM81qgmdoiiVEO5hlmOZpoBoC7tvqGh_eQpcbonYXoBwVQKtWzLzz3C5bvh4aug55Q

< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/event-stream;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Mon, 19 Nov 2018 23:41:55 GMT
<

`

Hi Troy,

I think this is related to the how you’re reacting to the exception within your Flux. I am not a Project Reactor expert, so I’m not 100% sure on this, but it looks like throwing an exception from a handler in the flux chain is not the way to go. An error is a way for Reactor to notify that a Flux or Mono is ending because of a reported error somewhere. Throwing an exception will just cause the flux to end with an error (which it already did, so there is no further action).

I think the way to go, here, is to have your onError() step do the actual handling of the error, performing whatever action you need. This is probably creating an error message on your server-sent-events stream and/or closing it.

Finally, I would use concatWith() instead of mergeWith(), so that initial results are guaranteed to be reported before any updates.

Hope this helps,

Allard

I’m not following. Perhaps my original message was confusing. There isn’t an exception in the Flux part, the exception is raised in the actual execution of the @QueryHandler method, which is executed by the axon subscription query code, in order to fetch the initial result.

The problem is that while I can monitor the logs and see that the exception has occurred (see stacktrace on previous message), I can not seem to trap the error in my REST controller. The REST controller looks like this:

`

@GetMapping(path = “/{id}”, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux packageRecordSubscription(@PathVariable String id) {
Assert.hasText(id, “null/blank id (package identifier)”);
SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult = subscribeToPackageRecord(id);
return queryResult.initialResult().doOnError(e -> {
throw new RuntimeException(e);
}).concatWith(queryResult.updates());
}

`

The subscribeToPackageRecord() method here:

`

private SubscriptionQueryResult<PackageRecord, PackageRecord> subscribeToPackageRecord(String pkgId) {
SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult =
queryGateway.subscriptionQuery(new PackageRecordByIdQuery(pkgId), ResponseTypes.instanceOf(PackageRecord.class),
ResponseTypes.instanceOf(PackageRecord.class));
return queryResult;
}

`

The problem is that the doOnError() step is never executed because the subscription query machinery doesn’t seem to notify that the exception happened in the query handler.

My rest controllers are configured with controller advice which will handle NoSuchElementException by returning a 404. So that is why I would ultimately like to re-throw the exception from the @QueryHandler method in question.

Re-reading your message I think I may not have understood what you mean the first time I read your response. Are you saying that my QueryHandler should raise an Error vs an Exception?

I tried this out, but there’s no change in behavior. I still can’t determine there is a problem from the REST controller code.

Hi Troy,

I think I found the culprit. This explains the “works on my machine”:
https://github.com/AxonFramework/AxonFramework/pull/904

We’ll fix this in 4.0.2, which we will release shortly.

Cheers,

Allard

Hi Troy,

Axon Framework 4.0.2 is just out. This release contains a fix for cases where an illegal null value was included in exception messages.
Can you confirm if this also solves your issue?

Cheers,

Allard

4.0.2 does not address my issue. With this version, I’ve tried with my QueryHandler throwing an Error and also with it throwing the NoSuchElementException (which I prefer) but it doesn’t seem to make a difference.

Does the code for my controller look correct for trapping the error that occurs fetching the initial result? I know that state of the code is not exactly what I’m going to want, I just need to know if it demonstrates how I can trap an exception/error from the QueryHandler responsible for providing the initial result. Code below for convenience:

`

@GetMapping(path = “/{id}”, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux packageRecordSubscription(@PathVariable String id) {
Assert.hasText(id, “null/blank id (package identifier)”);

SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult = subscribeToPackageRecord(id);
return queryResult.initialResult().doOnError(e -> {
throw new RuntimeException(e);

}).concatWith(queryResult.updates());
}

private SubscriptionQueryResult<PackageRecord, PackageRecord> subscribeToPackageRecord(String pkgId) {
SubscriptionQueryResult<PackageRecord, PackageRecord> queryResult =
queryGateway.subscriptionQuery(new PackageRecordByIdQuery(pkgId), ResponseTypes.instanceOf(PackageRecord.class),
ResponseTypes.instanceOf(PackageRecord.class));
return queryResult;
}

`

FYI: I’m sure this is not related to my issue, but I noticed that the axon-mongo artifact didn’t get a 4.0.2 release – at least I can’t see it on maven central. So I manually set it’s version to 4.0. Question: will you be providing a 4.0.2 version for that artifact?

Cheers,

Troy

Hi Troy,

I found the culprit: https://github.com/AxonFramework/AxonFramework/issues/913

The SimpleQueryBus isn’t reporting exceptions correctly for subscription queries.
We’ll fix this in 4.0.3.

Kind regards,

Allard

Thank you! I’ll watch for that release.

Any word on the state of this issue? I’ve tried the new 4.0.3 release, but it doesn’t solve the issue. I’m not sure if this is ready yet though, because not all of the axon artifacts have a 4.0.3 release. In my case I have to specify version 4.0 for the “axon-mongo” artifact.

Hi Troy,

We assumed the issue Allard opened up would resolve the problem at hand here, sorry to hear it didn’t

Would you mind opening up an issue, providing the necessary description, so that we can try to figure this out further?

Cheers,
Steven