[[post-processing-after-sending-message]]
= Post processing (after sending message)

Once function is invoked, its result is sent by the framework to a target destination which effectively completes function invocation cycle. 

However such cycle may not be fully complete from the business standpoint until some additional tasks are performed *after* completion of this cycle. 
While this could be accomplished with a simple combination of `Consumer` and `StreamBridge` as described in this 
https://stackoverflow.com/questions/75917883/post-processing-after-spring-cloud-stream-function[Stack Overflow post], since version 4.0.3 the framework 
provides a more idiomatic approach to solve this issue via `PostProcessingFunction` provided by Spring Cloud Function project.
The `PostProcessingFunction` is a special semi-marker function which contains one additional method `postProcess(Message>)` designed 
to provide a place for implementing such post processing task. 

----
package org.springframework.cloud.function.context
. . .
public interface PostProcessingFunction<I, O> extends Function<I, O> {
	default void postProcess(Message<O> result) {
	}
}
----

So, now you have two options.

Option 1: You can implement your function as `PostProcessingFunction` and also include the additional post processing behavior by implementing its `postProcess(Message>)` method.

----
private static class Uppercase implements PostProcessingFunction<String, String> {

	@Override
	public String apply(String input) {
		return input.toUpperCase();
	}

	@Override
	public void postProcess(Message<String> result) {
		System.out.println("Function Uppercase has been successfully invoked and its result successfully sent to target destination");
	}
}
. . .
@Bean
public Function<String, String> uppercase() {
	return new Uppercase();
}
----

Option 2: If you already have an existing function and don't want to change its implementation or want to keep your function as POJO, you can simply implement only `postProcess(Message>)` method and compose this new post processing function with your other function.
----
private static class Logger implements PostProcessingFunction<?, String> {

	@Override
	public void postProcess(Message<String> result) {
		System.out.println("Function has been successfully invoked and its result successfully sent to target destination");
	}
}
. . .
@Bean
public Function<String, String> uppercase() {
	return v -> v.toUpperCase();
}
@Bean
public Function<String, String> logger() {
	return new Logger();
}
. . .
//  and then have your function definition as such `uppercase|logger`
----

NOTE: 
In case of function composition only the last instance of `PostProcessingFunction` (if present) will take effect. For example, let's say you have the 
following function definition - `foo|bar|baz` and both `foo` and `baz` are instances of `PostProcessingFunction`. Only `baz.postProcess(Message>)` will be invoked.
If `baz` is not an instance of `PostProcessingFunction`, then no post processing functionality will be performed. 

One may argue that you can easily do that via function composition by simply composing a post-processor as just another `Function`. That is indeed a possibility however 
the post processing functionality in this case will be invoked right after invocation of the previous function and before the message is sent to a target destination
which is before the function invocation cycle is complete.

