Fire build event service event when we complete the build event lifecycle or fail to publish build events to the build event service.

RELNOTES: None.
PiperOrigin-RevId: 320059960
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
index 3eb1748..cb0ba3e 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
@@ -11,6 +11,16 @@
 )
 
 java_library(
+    name = "BuildEventServiceAvailabilityEvent",
+    srcs = ["BuildEventServiceAvailabilityEvent.java"],
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib/util:exit_code",
+        "//src/main/protobuf:failure_details_java_proto",
+        "//third_party:jsr305",
+    ],
+)
+
+java_library(
     name = "buildeventservice-options",
     srcs = ["BuildEventServiceOptions.java"],
     deps = [
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceAvailabilityEvent.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceAvailabilityEvent.java
new file mode 100644
index 0000000..f9d66d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceAvailabilityEvent.java
@@ -0,0 +1,54 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.buildeventservice;
+
+import com.google.devtools.build.lib.server.FailureDetails.BuildProgress;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.util.ExitCode;
+import javax.annotation.Nullable;
+
+/** Event fired from {@link BuildEventServiceUploader}. */
+public class BuildEventServiceAvailabilityEvent {
+  private final ExitCode exitCode;
+  @Nullable private final FailureDetail failureDetail;
+
+  public BuildEventServiceAvailabilityEvent(
+      ExitCode exitCode, @Nullable FailureDetail failureDetail) {
+    this.exitCode = exitCode;
+    this.failureDetail = failureDetail;
+  }
+
+  public static BuildEventServiceAvailabilityEvent ofSuccess() {
+    return new BuildEventServiceAvailabilityEvent(ExitCode.SUCCESS, null);
+  }
+
+  /**
+   * Returns {@link ExitCode.SUCCESS} if the build event upload was a success, otherwise, return an
+   * exit code that corresponds to the error that occurred during the build event upload.
+   */
+  public ExitCode getExitCode() {
+    return exitCode;
+  }
+
+  /**
+   * Returns a failure detail containing the status of the build event that was uploaded to the
+   * build event service. This returns null if the upload completed successfully, otherwise, the
+   * contents will contain an {@link ExitCode} and a {@link BuildProgress.Code}.
+   */
+  @Nullable
+  public FailureDetail getFailureDetail() {
+    return failureDetail;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
index 4c830e3..ee2edba 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceUploader.java
@@ -272,7 +272,7 @@
     return halfCloseFuture;
   }
 
-  private void logAndExitAbruptly(
+  private DetailedExitCode logAndSetException(
       String message, ExitCode exitCode, BuildProgress.Code bpCode, Throwable cause) {
     checkState(!exitCode.equals(ExitCode.SUCCESS));
     logger.atSevere().log(message);
@@ -284,6 +284,7 @@
                 .setBuildProgress(BuildProgress.newBuilder().setCode(bpCode).build())
                 .build());
     closeFuture.setException(new AbruptExitException(detailedExitCode, cause));
+    return detailedExitCode;
   }
 
   @Override
@@ -306,27 +307,34 @@
           publishLifecycleEvent(besProtoUtil.buildFinished(currentTime(), buildStatus));
         }
       }
+      eventBus.post(BuildEventServiceAvailabilityEvent.ofSuccess());
     } catch (InterruptedException e) {
-      logger.atInfo().log("Aborting the BES upload due to having received an interrupt");
       synchronized (lock) {
         Preconditions.checkState(
             interruptCausedByCancel, "Unexpected interrupt on BES uploader thread");
       }
     } catch (DetailedStatusException e) {
-      logAndExitAbruptly(
-          e.extendedMessage,
-          shouldRetryStatus(e.getStatus())
+      boolean isTransient = shouldRetryStatus(e.getStatus());
+      ExitCode exitCode =
+          isTransient
               ? ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR
-              : ExitCode.PERSISTENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
-          e.bpCode,
-          e);
+              : ExitCode.PERSISTENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR;
+      DetailedExitCode detailedExitCode =
+          logAndSetException(e.extendedMessage, exitCode, e.bpCode, e);
+      eventBus.post(
+          new BuildEventServiceAvailabilityEvent(exitCode, detailedExitCode.getFailureDetail()));
     } catch (LocalFileUploadException e) {
       Throwables.throwIfUnchecked(e.getCause());
-      logAndExitAbruptly(
-          "The Build Event Protocol local file upload failed:",
-          ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
-          BuildProgress.Code.BES_UPLOAD_LOCAL_FILE_ERROR,
-          e.getCause());
+      DetailedExitCode detailedExitCode =
+          logAndSetException(
+              "The Build Event Protocol local file upload failed:",
+              ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
+              BuildProgress.Code.BES_UPLOAD_LOCAL_FILE_ERROR,
+              e.getCause());
+      eventBus.post(
+          new BuildEventServiceAvailabilityEvent(
+              ExitCode.TRANSIENT_BUILD_EVENT_SERVICE_UPLOAD_ERROR,
+              detailedExitCode.getFailureDetail()));
     } catch (Throwable e) {
       closeFuture.setException(e);
       logger.atSevere().log("BES upload failed due to a RuntimeException / Error. This is a bug.");