/* * Copyright 2017-present Facebook, Inc. * * Licensed 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 com.facebook.buck.distributed; import com.facebook.buck.distributed.thrift.FinishedBuildingResponse; import com.facebook.buck.distributed.thrift.GetTargetsToBuildResponse; import com.facebook.buck.distributed.thrift.StampedeId; import com.facebook.buck.log.Logger; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.Random; public class MinionModeRunner implements DistBuildModeRunner { private static final Logger LOG = Logger.get(MinionModeRunner.class); private static final int RETRY_BACKOFF_MILLIS = 1000; private final String coordinatorAddress; private final int coordinatorPort; private final LocalBuilder builder; private final StampedeId stampedeId; public MinionModeRunner( String coordinatorAddress, int coordinatorPort, LocalBuilder builder, StampedeId stampedeId) { this.builder = builder; this.stampedeId = stampedeId; Preconditions.checkArgument( coordinatorPort > 0, "The coordinator's port needs to be a positive integer."); this.coordinatorAddress = coordinatorAddress; this.coordinatorPort = coordinatorPort; } @Override public int runAndReturnExitCode() throws IOException, InterruptedException { try (ThriftCoordinatorClient client = new ThriftCoordinatorClient(coordinatorAddress, coordinatorPort, stampedeId)) { client.start(); final String minionId = generateNewMinionId(); while (true) { GetTargetsToBuildResponse response = client.getTargetsToBuild(minionId); switch (response.getAction()) { case BUILD_TARGETS: List<String> targetsToBuild = Lists.newArrayList(response.getBuildTargets()); LOG.debug( String.format( "Minion [%s] is about to build [%d] targets: [%s]", minionId, targetsToBuild.size(), Joiner.on(", ").join(targetsToBuild))); int buildExitCode = builder.buildLocallyAndReturnExitCode(targetsToBuild); LOG.debug( String.format( "Minion [%s] finished with exit code [%d].", minionId, buildExitCode)); FinishedBuildingResponse finishedResponse = client.finishedBuilding(minionId, buildExitCode); if (!finishedResponse.isContinueBuilding()) { return 0; } break; case RETRY_LATER: try { Thread.sleep(RETRY_BACKOFF_MILLIS); } catch (InterruptedException e) { throw new RuntimeException(e); } break; case CLOSE_CLIENT: return 0; case UNKNOWN: default: throw new RuntimeException( String.format( "CoordinatorClient received unexpected action [%s].", response.getAction())); } } } } public static String generateNewMinionId() throws UnknownHostException { String hostname = "Unknown"; try { InetAddress addr; addr = InetAddress.getLocalHost(); hostname = addr.getHostName(); } catch (UnknownHostException ex) { System.out.println("Hostname can not be resolved"); } return String.format("minion:%s:%d", hostname, new Random().nextInt(Integer.MAX_VALUE)); } }