Skip to content

.log() should always behave the same, no matter where it is placed in a flow #3615

@swiss-chris

Description

@swiss-chris

Expected Behavior

Given some code like this:

        .scatterGather(
                scatterer -> scatterer
                        .applySequence(true)
                        .recipientFlow(IntegrationFlows.from(MessageChannels.executor(myExecutorService))
                                .gateway(mySubFlow1())
                                .get())
                        .recipientFlow(IntegrationFlows.from(MessageChannels.executor(myExecutorService))
                                .log(/* some logging here */)
                                .gateway(mySubFlow2())
                                .get()),
                gatherer -> gatherer
                        .releaseStrategy(defaultReleaseStrategy)
                        .outputProcessor(myOutputProcessor))

if I move the .log() statement down one line, like this:

        .scatterGather(
                scatterer -> scatterer
                        .applySequence(true)
                        .recipientFlow(IntegrationFlows.from(MessageChannels.executor(myExecutorService))
                                .gateway(mySubFlow1())
                                .get())
                        .recipientFlow(IntegrationFlows.from(MessageChannels.executor(myExecutorService))
                                .gateway(mySubFlow2())
                                .log(/* some logging here */)
                                .get()),
                gatherer -> gatherer
                        .releaseStrategy(defaultReleaseStrategy)
                        .outputProcessor(myOutputProcessor))

I would expect everything to work exactly the same, except that the .log() statement is executed after the .gateway() call.

Current Behavior

Changing the position of .log() changes the behavior of the flow. In this case, the releaseStrategy never receives the output of the second recipientFlow. The reason for this is explained in the JavaDoc, where we read - "When this operator is used in the end of flow, it is treated as one-way handler without any replies to continue.".

Context

This is not the behavior one would expect, it's not intuitive, and it has caused an unexpected bug in our team that took a long time to debug. (https://en.m.wikipedia.org/wiki/Principle_of_least_astonishment) We were quite surprised to learn about .logAndReply() and consider it one of those things that make the SI DSL hard to work with. Sometimes things just don't work and you have not reason why and no easy and no quick way to find the cause.

IMO the .log() statement should behave the same no matter where you place it in a flow. If it is placed at the end of a flow, and if this flow has no output channel, throw the usual exception, and the developer will quickly realize they need to add .nullChannel() or something similar. Perhaps you could even detect if .log() needs to reply or not (it seems you can detect if it is at the end of a flow, so maybe at that moment you can also detect if an output channel is configured for this flow) ?

logAndReply() could be deprecated and ultimately removed.

Am I missing something that would prevent such a solution ?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions