Encode remaining SimpleSpawnResult failures with FailureDetails
RELNOTES: None.
PiperOrigin-RevId: 318514673
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BUILD b/src/main/java/com/google/devtools/build/lib/exec/BUILD
index 9251478..eabf79f 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/exec/BUILD
@@ -216,6 +216,7 @@
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/java/com/google/devtools/build/lib/util:exit_code",
+ "//src/main/protobuf:failure_details_java_proto",
"//third_party:guava",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
index 7c77636..ae9b7a9 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnExecException.java
@@ -22,6 +22,9 @@
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.actions.SpawnResult.Status;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.Spawn;
+import com.google.devtools.build.lib.server.FailureDetails.Spawn.Code;
import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.ExitCode;
@@ -77,7 +80,12 @@
ExitCode exitCode =
result.status().isConsideredUserError() ? ExitCode.BUILD_FAILURE : ExitCode.REMOTE_ERROR;
if (result.failureDetail() == null) {
- return DetailedExitCode.justExitCode(exitCode);
+ return DetailedExitCode.of(
+ exitCode,
+ FailureDetail.newBuilder()
+ .setMessage("spawn failed")
+ .setSpawn(Spawn.newBuilder().setCode(Code.UNSPECIFIED_EXECUTION_FAILURE))
+ .build());
}
return DetailedExitCode.of(exitCode, result.failureDetail());
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
index 7966e08..649e24a 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
@@ -74,6 +74,8 @@
import com.google.devtools.build.lib.remote.util.TracingMetadataUtils;
import com.google.devtools.build.lib.remote.util.Utils;
import com.google.devtools.build.lib.remote.util.Utils.InMemoryOutput;
+import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.Path;
@@ -602,16 +604,31 @@
.setRunnerName(getName())
.setStatus(Status.TIMEOUT)
.setExitCode(SpawnResult.POSIX_TIMEOUT_EXIT_CODE)
+ .setFailureDetail(
+ FailureDetail.newBuilder()
+ .setMessage("remote spawn timed out")
+ .setSpawn(
+ FailureDetails.Spawn.newBuilder()
+ .setCode(FailureDetails.Spawn.Code.TIMEOUT))
+ .build())
.build();
}
}
final Status status;
+ FailureDetails.Spawn.Code detailedCode;
+ boolean catastrophe;
if (RemoteRetrierUtils.causedByStatus(exception, Code.UNAVAILABLE)) {
status = Status.EXECUTION_FAILED_CATASTROPHICALLY;
+ detailedCode = FailureDetails.Spawn.Code.EXECUTION_FAILED;
+ catastrophe = true;
} else if (remoteCacheFailed) {
status = Status.REMOTE_CACHE_FAILED;
+ detailedCode = FailureDetails.Spawn.Code.REMOTE_CACHE_FAILED;
+ catastrophe = false;
} else {
status = Status.EXECUTION_FAILED;
+ detailedCode = FailureDetails.Spawn.Code.EXECUTION_FAILED;
+ catastrophe = false;
}
final String errorMessage;
@@ -627,6 +644,14 @@
.setStatus(status)
.setExitCode(ExitCode.REMOTE_ERROR.getNumericExitCode())
.setFailureMessage(errorMessage)
+ .setFailureDetail(
+ FailureDetail.newBuilder()
+ .setMessage("remote spawn failed: " + errorMessage)
+ .setSpawn(
+ FailureDetails.Spawn.newBuilder()
+ .setCode(detailedCode)
+ .setCatastrophic(catastrophe))
+ .build())
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/util/BUILD b/src/main/java/com/google/devtools/build/lib/remote/util/BUILD
index 7612bda..e727163 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/util/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/remote/util/BUILD
@@ -22,6 +22,7 @@
"//src/main/java/com/google/devtools/build/lib/remote/options",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+ "//src/main/protobuf:failure_details_java_proto",
"//third_party:guava",
"//third_party:jsr305",
"//third_party/grpc:grpc-jar",
diff --git a/src/main/java/com/google/devtools/build/lib/remote/util/Utils.java b/src/main/java/com/google/devtools/build/lib/remote/util/Utils.java
index c6b6357..71847e7 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/util/Utils.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/util/Utils.java
@@ -29,6 +29,9 @@
import com.google.devtools.build.lib.remote.common.CacheNotFoundException;
import com.google.devtools.build.lib.remote.common.RemoteCacheClient.ActionKey;
import com.google.devtools.build.lib.remote.options.RemoteOutputsMode;
+import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.Spawn.Code;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -98,6 +101,13 @@
.setCacheHit(cacheHit)
.setSpawnMetrics(spawnMetrics)
.setRemote(true);
+ if (exitCode != 0) {
+ builder.setFailureDetail(
+ FailureDetail.newBuilder()
+ .setMessage("remote spawn failed")
+ .setSpawn(FailureDetails.Spawn.newBuilder().setCode(Code.NON_ZERO_EXIT))
+ .build());
+ }
if (inMemoryOutput != null) {
builder.setInMemoryOutput(inMemoryOutput.getOutput(), inMemoryOutput.getContents());
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
index 886f82c..8807993 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
@@ -36,6 +36,7 @@
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.SilentCloseable;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
+import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Sandbox;
import com.google.devtools.build.lib.server.FailureDetails.Sandbox.Code;
@@ -193,11 +194,13 @@
.getErrorStream()
.write(("Action failed to execute: java.io.IOException: " + msg + "\n").getBytes(UTF_8));
outErr.getErrorStream().flush();
+ String message = makeFailureMessage(originalSpawn, sandbox);
return new SpawnResult.Builder()
.setRunnerName(getName())
.setStatus(Status.EXECUTION_FAILED)
.setExitCode(LOCAL_EXEC_ERROR)
- .setFailureMessage(makeFailureMessage(originalSpawn, sandbox))
+ .setFailureMessage(message)
+ .setFailureDetail(createFailureDetail(message, Code.EXECUTION_FAILED))
.build();
}
@@ -206,12 +209,40 @@
boolean wasTimeout =
(useSubprocessTimeout && terminationStatus.timedOut())
|| (!useSubprocessTimeout && wasTimeout(timeout, wallTime));
- int exitCode =
- wasTimeout ? SpawnResult.POSIX_TIMEOUT_EXIT_CODE : terminationStatus.getRawExitCode();
- Status status =
- wasTimeout
- ? Status.TIMEOUT
- : (exitCode == 0) ? Status.SUCCESS : Status.NON_ZERO_EXIT;
+
+ int exitCode;
+ Status status;
+ String failureMessage;
+ FailureDetail failureDetail;
+ if (wasTimeout) {
+ exitCode = SpawnResult.POSIX_TIMEOUT_EXIT_CODE;
+ status = Status.TIMEOUT;
+ failureMessage = makeFailureMessage(originalSpawn, sandbox);
+ failureDetail =
+ FailureDetail.newBuilder()
+ .setMessage(failureMessage)
+ .setSpawn(
+ FailureDetails.Spawn.newBuilder().setCode(FailureDetails.Spawn.Code.TIMEOUT))
+ .build();
+ } else {
+ exitCode = terminationStatus.getRawExitCode();
+ if (exitCode == 0) {
+ status = Status.SUCCESS;
+ failureMessage = "";
+ failureDetail = null;
+ } else {
+ status = Status.NON_ZERO_EXIT;
+ failureMessage = makeFailureMessage(originalSpawn, sandbox);
+ failureDetail =
+ FailureDetail.newBuilder()
+ .setMessage(failureMessage)
+ .setSpawn(
+ FailureDetails.Spawn.newBuilder()
+ .setCode(FailureDetails.Spawn.Code.NON_ZERO_EXIT)
+ .setSpawnExitCode(exitCode))
+ .build();
+ }
+ }
SpawnResult.Builder spawnResultBuilder =
new SpawnResult.Builder()
@@ -219,10 +250,11 @@
.setStatus(status)
.setExitCode(exitCode)
.setWallTime(wallTime)
- .setFailureMessage(
- status != Status.SUCCESS || exitCode != 0
- ? makeFailureMessage(originalSpawn, sandbox)
- : "");
+ .setFailureMessage(failureMessage);
+
+ if (failureDetail != null) {
+ spawnResultBuilder.setFailureDetail(failureDetail);
+ }
Path statisticsPath = sandbox.getStatisticsPath();
if (statisticsPath != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
index 898a6ac..bdb9b1d 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
@@ -33,6 +33,7 @@
import com.google.devtools.build.lib.actions.SpawnExecutedEvent;
import com.google.devtools.build.lib.actions.SpawnMetrics;
import com.google.devtools.build.lib.actions.SpawnResult;
+import com.google.devtools.build.lib.actions.SpawnResult.Status;
import com.google.devtools.build.lib.actions.Spawns;
import com.google.devtools.build.lib.actions.UserExecException;
import com.google.devtools.build.lib.events.Event;
@@ -209,19 +210,28 @@
response.getOutputBytes().writeTo(outErr.getErrorStream());
int exitCode = response.getExitCode();
- SpawnResult result =
+ SpawnResult.Builder builder =
new SpawnResult.Builder()
.setRunnerName(getName())
.setExitCode(exitCode)
- .setStatus(
- exitCode == 0 ? SpawnResult.Status.SUCCESS : SpawnResult.Status.NON_ZERO_EXIT)
+ .setStatus(exitCode == 0 ? Status.SUCCESS : Status.NON_ZERO_EXIT)
.setWallTime(wallTime)
.setSpawnMetrics(
SpawnMetrics.Builder.forWorkerExec()
.setTotalTime(wallTime)
.setExecutionWallTime(wallTime)
- .build())
- .build();
+ .build());
+ if (exitCode != 0) {
+ builder.setFailureDetail(
+ FailureDetail.newBuilder()
+ .setMessage("worker spawn failed")
+ .setSpawn(
+ FailureDetails.Spawn.newBuilder()
+ .setCode(FailureDetails.Spawn.Code.NON_ZERO_EXIT)
+ .setSpawnExitCode(exitCode))
+ .build());
+ }
+ SpawnResult result = builder.build();
reporter.post(new SpawnExecutedEvent(spawn, result, startTime));
return result;
}
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 7beafc6..d125f39 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -205,6 +205,9 @@
INVALID_TIMEOUT = 9 [(metadata) = { exit_code: 1 }];
INVALID_REMOTE_EXECUTION_PROPERTIES = 10 [(metadata) = { exit_code: 1 }];
NO_USABLE_STRATEGY_FOUND = 11 [(metadata) = { exit_code: 1 }];
+ // TODO(b/138456686): this code should be deprecated when SpawnResult is
+ // refactored to prohibit undetailed failures
+ UNSPECIFIED_EXECUTION_FAILURE = 12 [(metadata) = { exit_code: 1 }];
}
Code code = 1;
@@ -653,6 +656,7 @@
MOUNT_SOURCE_DOES_NOT_EXIST = 7 [(metadata) = { exit_code: 1 }];
MOUNT_SOURCE_TARGET_TYPE_MISMATCH = 8 [(metadata) = { exit_code: 1 }];
MOUNT_TARGET_DOES_NOT_EXIST = 9 [(metadata) = { exit_code: 1 }];
+ EXECUTION_FAILED = 10 [(metadata) = { exit_code: 1 }];
}
Code code = 1;