org.apache.flink.runtime.dispatcher.runner.AbstractDispatcherLeaderProcess Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.flink.runtime.dispatcher.runner;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.api.common.JobID;
import org.apache.flink.runtime.clusterframework.ApplicationStatus;
import org.apache.flink.runtime.concurrent.FutureUtils;
import org.apache.flink.runtime.dispatcher.DispatcherGateway;
import org.apache.flink.runtime.dispatcher.DispatcherId;
import org.apache.flink.runtime.jobgraph.JobGraph;
import org.apache.flink.runtime.jobmanager.JobGraphWriter;
import org.apache.flink.runtime.rpc.FatalErrorHandler;
import org.apache.flink.runtime.webmonitor.RestfulGateway;
import org.apache.flink.util.AutoCloseableAsync;
import org.apache.flink.util.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.Supplier;
abstract class AbstractDispatcherLeaderProcess implements DispatcherLeaderProcess {
protected final Logger log = LoggerFactory.getLogger(getClass());
private final Object lock = new Object();
private final UUID leaderSessionId;
private final FatalErrorHandler fatalErrorHandler;
private final CompletableFuture dispatcherGatewayFuture;
private final CompletableFuture leaderAddressFuture;
private final CompletableFuture terminationFuture;
private final CompletableFuture shutDownFuture;
private State state;
@Nullable
private DispatcherGatewayService dispatcherService;
AbstractDispatcherLeaderProcess(UUID leaderSessionId, FatalErrorHandler fatalErrorHandler) {
this.leaderSessionId = leaderSessionId;
this.fatalErrorHandler = fatalErrorHandler;
this.dispatcherGatewayFuture = new CompletableFuture<>();
this.leaderAddressFuture = dispatcherGatewayFuture.thenApply(RestfulGateway::getAddress);
this.terminationFuture = new CompletableFuture<>();
this.shutDownFuture = new CompletableFuture<>();
this.state = State.CREATED;
}
@VisibleForTesting
State getState() {
synchronized (lock) {
return state;
}
}
@Override
public final void start() {
runIfStateIs(
State.CREATED,
this::startInternal);
}
private void startInternal() {
log.info("Start {}.", getClass().getSimpleName());
state = State.RUNNING;
onStart();
}
@Override
public final UUID getLeaderSessionId() {
return leaderSessionId;
}
@Override
public final CompletableFuture getDispatcherGateway() {
return dispatcherGatewayFuture;
}
@Override
public final CompletableFuture getLeaderAddressFuture() {
return leaderAddressFuture;
}
@Override
public CompletableFuture getShutDownFuture() {
return shutDownFuture;
}
protected final Optional getDispatcherService() {
return Optional.ofNullable(dispatcherService);
}
@Override
public final CompletableFuture closeAsync() {
runIfStateIsNot(
State.STOPPED,
this::closeInternal);
return terminationFuture;
}
private void closeInternal() {
log.info("Stopping {}.", getClass().getSimpleName());
final CompletableFuture dispatcherServiceTerminationFuture = closeDispatcherService();
final CompletableFuture onCloseTerminationFuture = FutureUtils.composeAfterwards(
dispatcherServiceTerminationFuture,
this::onClose);
FutureUtils.forward(
onCloseTerminationFuture,
this.terminationFuture);
state = State.STOPPED;
}
private CompletableFuture closeDispatcherService() {
if (dispatcherService != null) {
return dispatcherService.closeAsync();
} else {
return FutureUtils.completedVoidFuture();
}
}
protected abstract void onStart();
protected CompletableFuture onClose() {
return FutureUtils.completedVoidFuture();
}
final void completeDispatcherSetup(DispatcherGatewayService dispatcherService) {
runIfStateIs(
State.RUNNING,
() -> completeDispatcherSetupInternal(dispatcherService));
}
private void completeDispatcherSetupInternal(DispatcherGatewayService createdDispatcherService) {
Preconditions.checkState(dispatcherService == null, "The DispatcherGatewayService can only be set once.");
dispatcherService = createdDispatcherService;
dispatcherGatewayFuture.complete(createdDispatcherService.getGateway());
FutureUtils.forward(createdDispatcherService.getShutDownFuture(), shutDownFuture);
}
final Optional supplyUnsynchronizedIfRunning(Supplier supplier) {
synchronized (lock) {
if (state != State.RUNNING) {
return Optional.empty();
}
}
return Optional.of(supplier.get());
}
final Optional supplyIfRunning(Supplier supplier) {
synchronized (lock) {
if (state != State.RUNNING) {
return Optional.empty();
}
return Optional.of(supplier.get());
}
}
final void runIfStateIs(State expectedState, Runnable action) {
runIfState(expectedState::equals, action);
}
private void runIfStateIsNot(State notExpectedState, Runnable action) {
runIfState(
state -> !notExpectedState.equals(state),
action);
}
private void runIfState(Predicate actionPredicate, Runnable action) {
synchronized (lock) {
if (actionPredicate.test(state)) {
action.run();
}
}
}
final Void onErrorIfRunning(T ignored, Throwable throwable) {
synchronized (lock) {
if (state != State.RUNNING) {
return null;
}
}
if (throwable != null) {
closeAsync();
fatalErrorHandler.onFatalError(throwable);
}
return null;
}
protected enum State {
CREATED,
RUNNING,
STOPPED
}
// ------------------------------------------------------------
// Internal classes
// ------------------------------------------------------------
interface DispatcherGatewayServiceFactory {
DispatcherGatewayService create(
DispatcherId fencingToken,
Collection recoveredJobs,
JobGraphWriter jobGraphWriter);
}
interface DispatcherGatewayService extends AutoCloseableAsync {
DispatcherGateway getGateway();
CompletableFuture onRemovedJobGraph(JobID jobId);
CompletableFuture getShutDownFuture();
}
}