Skip to content

@Subscribe-r of the rejection caused by a particular command causes the dispatching failure in some cases #1318

Closed
@armiol

Description

@armiol

Landscape

It is possible to subscribe to a rejection which is caused by some command:

public class CancellationWatch extends AbstractEventSubscriber {

    @Subscribe
    void on(Rejections.OrderAlreadyCompleted r, CancelOrder c) {
        ...
    }
}

In this example, a subscriber wants to consume only those OrderAlreadyCompleted rejections which are thrown while handling order cancellations (hence, CancelOrder command is the second argument).

At the same time, it is also possible to declare several command handlers which would throw a rejection of the same type:

public class OrderAggregate extends Aggregate<OrderId, Order, Order.Builder> {

    @Assign
    OrderCompleted handle(CompleteOrder c) throws OrderAlreadyCompleted {
        ...
    }

    @Assign
    OrderCancelled handle(CancelOrder c) throws OrderAlreadyCompleted {
        ...
    }
}

In the example above, the OrderAggregate rejects all commands with OrderAlreadyCompleted if the order is already completed.

Action

Now, if some completed order handles CompleteOrder command, the aggregate throws a OrderAlreadyCompleted rejection. In theory, if anyone has subscribed to this rejection, they would receive it.

But, one thing for sure, CancellationWatch is not interested in this rejection—because the origin command is not what it expects.

So if no subscribers to OrderAlreadyCompleted rejection is found, it should just pass through the event bus, just as any other rejection or event.

Issue

In reality, the framework attempts to select the handler for this rejection anyway, and fails to do so:

java.lang.IllegalStateException: Unable to find handler with the key: DispatchKey{messageClass=`com.acme.order.Rejections$OrderAlreadyCompleted}.
	at com.google.common.base.Preconditions.checkState(Preconditions.java:589)
	at io.spine.server.model.HandlerMap.handlersOf(HandlerMap.java:145)
	at io.spine.server.model.HandlerMap.handlersOf(HandlerMap.java:174)
	at io.spine.server.event.model.EventReceivingClassDelegate.handlersOf(EventReceivingClassDelegate.java:127)
	at io.spine.server.event.model.EventSubscriberClass.subscribersOf(EventSubscriberClass.java:79)
	at io.spine.server.event.model.SubscribingClass.subscriberOf(SubscribingClass.java:47)
	at io.spine.server.event.AbstractEventSubscriber.canDispatch(AbstractEventSubscriber.java:140)
	at io.spine.server.event.AbstractEventSubscriber.canDispatch(AbstractEventSubscriber.java:60)
	at io.spine.server.bus.DispatcherRegistry.lambda$dispatchersOf$0(DispatcherRegistry.java:105)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1556)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
	at io.spine.server.bus.DispatcherRegistry.dispatchersOf(DispatcherRegistry.java:107)
	at io.spine.server.bus.DeadMessageFilter.filter(DeadMessageFilter.java:56)
	at io.spine.server.bus.FilterChain.filter(FilterChain.java:57)
	at io.spine.server.bus.Bus.filter(Bus.java:296)
	at io.spine.server.bus.Bus.filter(Bus.java:272)
	at io.spine.server.bus.Bus.filterAndPost(Bus.java:150)
	at io.spine.server.bus.Bus.post(Bus.java:146)

The reason is as follows. From the dispatcher registry, the framework knows that someone does handle the rejections of this type. And from this point, it is going to get that someone. There is no option to discover that in fact that "someone" does not match the "origin message" criterion.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions