
io.numaproj.numaflow.reducer.ReduceActor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of numaflow-java Show documentation
Show all versions of numaflow-java Show documentation
SDK to implement Numaflow Source or User Defined Functions or Sinks in Java.
The newest version!
package io.numaproj.numaflow.reducer;
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.japi.pf.ReceiveBuilder;
import com.google.protobuf.ByteString;
import com.google.protobuf.Timestamp;
import io.numaproj.numaflow.reduce.v1.ReduceOuterClass;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Reduce actor invokes the reducer and returns the result.
*/
@Slf4j
@AllArgsConstructor
class ReduceActor extends AbstractActor {
private String[] keys;
private Metadata md;
private Reducer groupBy;
public static Props props(String[] keys, Metadata md, Reducer groupBy) {
return Props.create(ReduceActor.class, keys, md, groupBy);
}
@Override
public Receive createReceive() {
return ReceiveBuilder
.create()
.match(HandlerDatum.class, this::invokeHandler)
.match(String.class, this::getResult)
.build();
}
private void invokeHandler(HandlerDatum handlerDatum) {
this.groupBy.addMessage(keys, handlerDatum, md);
}
private void getResult(String eof) {
MessageList resultMessages = this.groupBy.getOutput(keys, md);
// send the result back to sender(parent actor)
resultMessages.getMessages().forEach(message -> {
getSender().tell(buildActorResponse(message), getSelf());
});
// send a response back with EOF set to true, indicating the reducer has finished the data aggregation.
getSender().tell(buildEOFActorResponse(), getSelf());
}
private ActorResponse buildActorResponse(Message message) {
ReduceOuterClass.ReduceResponse.Builder responseBuilder = ReduceOuterClass.ReduceResponse.newBuilder();
// set the window using the actor metadata.
responseBuilder.setWindow(ReduceOuterClass.Window.newBuilder()
.setStart(Timestamp.newBuilder()
.setSeconds(this.md.getIntervalWindow().getStartTime().getEpochSecond())
.setNanos(this.md.getIntervalWindow().getStartTime().getNano()))
.setEnd(Timestamp.newBuilder()
.setSeconds(this.md.getIntervalWindow().getEndTime().getEpochSecond())
.setNanos(this.md.getIntervalWindow().getEndTime().getNano()))
.setSlot("slot-0").build());
responseBuilder.setEOF(false);
// set the result.
responseBuilder.setResult(ReduceOuterClass.ReduceResponse.Result
.newBuilder()
.setValue(ByteString.copyFrom(message.getValue()))
.addAllKeys(message.getKeys()
== null ? new ArrayList<>() : Arrays.asList(message.getKeys()))
.addAllTags(
message.getTags() == null ? new ArrayList<>() : List.of(message.getTags()))
.build());
return new ActorResponse(responseBuilder.build());
}
private ActorResponse buildEOFActorResponse() {
ReduceOuterClass.ReduceResponse.Builder responseBuilder = ReduceOuterClass.ReduceResponse.newBuilder();
responseBuilder.setWindow(ReduceOuterClass.Window.newBuilder()
.setStart(Timestamp.newBuilder()
.setSeconds(this.md.getIntervalWindow().getStartTime().getEpochSecond())
.setNanos(this.md.getIntervalWindow().getStartTime().getNano()))
.setEnd(Timestamp.newBuilder()
.setSeconds(this.md.getIntervalWindow().getEndTime().getEpochSecond())
.setNanos(this.md.getIntervalWindow().getEndTime().getNano()))
.setSlot("slot-0").build());
responseBuilder.setEOF(true);
// set a dummy result with the keys.
responseBuilder.setResult(ReduceOuterClass.ReduceResponse.Result
.newBuilder()
.addAllKeys(List.of(this.keys))
.build());
return new ActorResponse(responseBuilder.build());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy