diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/FcmSender.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/FcmSender.java index 3f6345c35..402c982f7 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/FcmSender.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/FcmSender.java @@ -10,6 +10,7 @@ import com.google.api.core.ApiFutureCallback; import com.google.api.core.ApiFutures; import com.google.auth.oauth2.GoogleCredentials; import com.google.common.annotations.VisibleForTesting; +import com.google.common.util.concurrent.MoreExecutors; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.messaging.AndroidConfig; @@ -20,16 +21,24 @@ import com.google.firebase.messaging.MessagingErrorCode; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name; + public class FcmSender implements PushNotificationSender { private final ExecutorService executor; private final FirebaseMessaging firebaseMessagingClient; + private static final Timer SEND_NOTIFICATION_TIMER = Metrics.timer(name(FcmSender.class, "sendNotification")); + private static final Logger logger = LoggerFactory.getLogger(FcmSender.class); public FcmSender(ExecutorService executor, String credentials) throws IOException { @@ -67,9 +76,17 @@ public class FcmSender implements PushNotificationSender { builder.putData(key, pushNotification.data() != null ? pushNotification.data() : ""); - final ApiFuture sendFuture = firebaseMessagingClient.sendAsync(builder.build()); + final Instant start = Instant.now(); final CompletableFuture completableSendFuture = new CompletableFuture<>(); + final ApiFuture sendFuture = firebaseMessagingClient.sendAsync(builder.build()); + + // We want to record the time taken to send the push notification as directly as possible; executing this very small + // bit of non-blocking measurement on the sender thread lets us do that without picking up any confounding factors + // like having a callback waiting in an executor's queue. + sendFuture.addListener(() -> SEND_NOTIFICATION_TIMER.record(Duration.between(start, Instant.now())), + MoreExecutors.directExecutor()); + ApiFutures.addCallback(sendFuture, new ApiFutureCallback<>() { @Override public void onSuccess(final String result) {