All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.camunda.zeebe.scheduler.future.ActorFutureCollector Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Camunda License 1.0. You may not use this file
 * except in compliance with the Camunda License 1.0.
 */
package io.camunda.zeebe.scheduler.future;

import static java.util.Arrays.stream;
import static java.util.Collections.emptySet;

import io.camunda.zeebe.scheduler.ConcurrencyControl;
import io.camunda.zeebe.util.Either;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Aggregates a number of {@code ActorFuture} objects into a single one. The aggregated future is
 * completed when all individual futures have completed. If all futures complete with a value, the
 * aggregated future returns the ordered list of said values. If one or more complete exceptionally,
 * the aggregated future will complete exceptionally. The exception will have the exceptions of the
 * individual futures aas suppressed exceptions. If exceptions occur, this does not interrupt the
 * individual futures.
 *
 * 
 * var aggregated = of(future1, future2).stream().collect(new ActorFutureCollector<>(concurrencyControl));
 * 
* * @param type of the value of each future */ public final class ActorFutureCollector implements Collector, List>, ActorFuture>> { private final ConcurrencyControl concurrencyControl; public ActorFutureCollector(final ConcurrencyControl concurrencyControl) { this.concurrencyControl = Objects.requireNonNull(concurrencyControl); } @Override public Supplier>> supplier() { return ArrayList::new; } @Override public BiConsumer>, ActorFuture> accumulator() { return List::add; } @Override public BinaryOperator>> combiner() { return (listA, listB) -> { listA.addAll(listB); return listA; }; } @Override public Function>, ActorFuture>> finisher() { return futures -> new CompletionWaiter<>(concurrencyControl, futures).get(); } @Override public Set characteristics() { return emptySet(); } private static final class CompletionWaiter implements Supplier>> { private final ConcurrencyControl concurrencyControl; private final List> pendingFutures; private final Either[] results; private ActorFuture> aggregated; private CompletionWaiter( final ConcurrencyControl concurrencyControl, final List> pendingFutures) { this.concurrencyControl = concurrencyControl; this.pendingFutures = new ArrayList<>(pendingFutures); results = new Either[(pendingFutures.size())]; } @Override public ActorFuture> get() { aggregated = concurrencyControl.createFuture(); if (pendingFutures.isEmpty()) { aggregated.complete(Collections.emptyList()); } else { for (int index = 0; index < pendingFutures.size(); index++) { final var pendingFuture = pendingFutures.get(index); final var currentIndex = index; concurrencyControl.runOnCompletion( pendingFuture, (result, error) -> handleCompletion(pendingFuture, currentIndex, result, error)); } } return aggregated; } private void handleCompletion( final ActorFuture pendingFuture, final int currentIndex, final V result, final Throwable error) { pendingFutures.remove(pendingFuture); results[currentIndex] = error == null ? Either.right(result) : Either.left(error); if (pendingFutures.isEmpty()) { completeAggregatedFuture(); } } private void completeAggregatedFuture() { final var aggregatedResult = stream(results).collect(Either.collector()); if (aggregatedResult.isRight()) { aggregated.complete(aggregatedResult.get()); } else { final var exception = new Exception("Errors occurred, see suppressed exceptions for details"); aggregatedResult.getLeft().forEach(exception::addSuppressed); aggregated.completeExceptionally(exception); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy