From 7451e3788d1f7944323f6dcad6e404274bba166c Mon Sep 17 00:00:00 2001 From: Dagger Team Date: Wed, 24 Jun 2026 19:56:34 -0700 Subject: [PATCH] Add dependenciesRequested to ProducerMonitor Previously, custom monitors could track when a producer was requested and when its method executed, but there was no way to know when it finished requesting its own dependencies. This new hook bridges that gap, making it easier to trace execution relationships in complex production graphs. Now, * methodStarting & methodFinished can be used to set up/tear down a scope around producer method execution, and * requested & dependenciesRequested can be used to set up/tear down a scope around producer dependency collection. RELNOTES=Added dependenciesRequested to ProducerMonitor PiperOrigin-RevId: 937702779 --- .../AbstractProducesMethodProducer.java | 8 ++++- .../producers/monitoring/ProducerMonitor.java | 16 ++++++++++ .../monitoring/internal/Monitors.java | 20 ++++++++++++ .../producers/monitoring/MonitoringTest.java | 6 ++++ .../AbstractProducesMethodProducerTest.java | 2 ++ .../monitoring/internal/MonitorsTest.java | 32 +++++++++++++++++++ 6 files changed, 83 insertions(+), 1 deletion(-) diff --git a/dagger-producers/main/java/dagger/producers/internal/AbstractProducesMethodProducer.java b/dagger-producers/main/java/dagger/producers/internal/AbstractProducesMethodProducer.java index 95b8f8340da..7d13d9847d2 100644 --- a/dagger-producers/main/java/dagger/producers/internal/AbstractProducesMethodProducer.java +++ b/dagger-producers/main/java/dagger/producers/internal/AbstractProducesMethodProducer.java @@ -71,7 +71,13 @@ protected AbstractProducesMethodProducer( protected final ListenableFuture compute() { monitor = monitorProvider.get().producerMonitorFor(token); monitor.requested(); - ListenableFuture result = Futures.transformAsync(collectDependencies(), this, this); + ListenableFuture dependenciesFuture; + try { + dependenciesFuture = collectDependencies(); + } finally { + monitor.dependenciesRequested(); + } + ListenableFuture result = Futures.transformAsync(dependenciesFuture, this, this); monitor.addCallbackTo(result); return result; } diff --git a/dagger-producers/main/java/dagger/producers/monitoring/ProducerMonitor.java b/dagger-producers/main/java/dagger/producers/monitoring/ProducerMonitor.java index 2613e7b1fe0..4a7d21a9361 100644 --- a/dagger-producers/main/java/dagger/producers/monitoring/ProducerMonitor.java +++ b/dagger-producers/main/java/dagger/producers/monitoring/ProducerMonitor.java @@ -31,6 +31,8 @@ *

The lifecycle of the monitor, under normal conditions, is: *

    *
  • {@link #requested()} + *
  • {@link #dependenciesRequested()} + *
  • {@link #ready()} *
  • {@link #methodStarting()} *
  • The method is called *
  • {@link #methodFinished()} @@ -58,6 +60,9 @@ *
  • A requested *
  • B requested *
  • C requested + *
  • C dependenciesRequested + *
  • B dependenciesRequested + *
  • A dependenciesRequested *
  • C methodStarting *
  • C methodFinished *
  • C succeeded @@ -102,6 +107,17 @@ public abstract class ProducerMonitor { */ public void requested() {} + /** + * Called when all of the producer's dependencies have been requested. This will be called from + * the same thread as {@link #requested()}. + * + *

    When multiple monitors are installed, calls to this method will be in the reverse order from + * calls to {@link #requested()}. + * + *

    This implementation is a no-op. + */ + public void dependenciesRequested() {} + /** * Called when all of the producer's inputs are available. This is called regardless of whether * the inputs have succeeded or not; when the inputs have succeeded, this is called prior to diff --git a/dagger-producers/main/java/dagger/producers/monitoring/internal/Monitors.java b/dagger-producers/main/java/dagger/producers/monitoring/internal/Monitors.java index 13b438ade46..2195196169d 100644 --- a/dagger-producers/main/java/dagger/producers/monitoring/internal/Monitors.java +++ b/dagger-producers/main/java/dagger/producers/monitoring/internal/Monitors.java @@ -135,6 +135,15 @@ public void requested() { } } + @Override + public void dependenciesRequested() { + try { + delegate.dependenciesRequested(); + } catch (RuntimeException e) { + logProducerMonitorMethodException(e, delegate, "dependenciesRequested"); + } + } + @Override public void ready() { try { @@ -270,6 +279,17 @@ public void requested() { } } + @Override + public void dependenciesRequested() { + for (ProducerMonitor delegate : delegates.reverse()) { + try { + delegate.dependenciesRequested(); + } catch (RuntimeException e) { + logProducerMonitorMethodException(e, delegate, "dependenciesRequested"); + } + } + } + @Override public void ready() { for (ProducerMonitor delegate : delegates) { diff --git a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java b/javatests/dagger/functional/producers/monitoring/MonitoringTest.java index 4991e7e14df..8b7650c8ad7 100644 --- a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java +++ b/javatests/dagger/functional/producers/monitoring/MonitoringTest.java @@ -88,13 +88,16 @@ public void basicMonitoring() throws Exception { inOrder.verify(callServer2Monitor).requested(); inOrder.verify(callServer1Monitor).requested(); inOrder.verify(requestDataMonitor).requested(); + inOrder.verify(requestDataMonitor).dependenciesRequested(); inOrder.verify(requestDataMonitor).ready(); inOrder.verify(requestDataMonitor).methodStarting(); inOrder.verify(requestDataMonitor).methodFinished(); inOrder.verify(requestDataMonitor).succeeded("Hello, World!"); + inOrder.verify(callServer1Monitor).dependenciesRequested(); inOrder.verify(callServer1Monitor).ready(); inOrder.verify(callServer1Monitor).methodStarting(); inOrder.verify(callServer1Monitor).methodFinished(); + inOrder.verify(callServer2Monitor).dependenciesRequested(); verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); server1Future.set("server 1 response"); @@ -133,13 +136,16 @@ public void basicMonitoringWithFailure() throws Exception { inOrder.verify(callServer2Monitor).requested(); inOrder.verify(callServer1Monitor).requested(); inOrder.verify(requestDataMonitor).requested(); + inOrder.verify(requestDataMonitor).dependenciesRequested(); inOrder.verify(requestDataMonitor).ready(); inOrder.verify(requestDataMonitor).methodStarting(); inOrder.verify(requestDataMonitor).methodFinished(); inOrder.verify(requestDataMonitor).succeeded("Hello, World!"); + inOrder.verify(callServer1Monitor).dependenciesRequested(); inOrder.verify(callServer1Monitor).ready(); inOrder.verify(callServer1Monitor).methodStarting(); inOrder.verify(callServer1Monitor).methodFinished(); + inOrder.verify(callServer2Monitor).dependenciesRequested(); verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); RuntimeException cause = new RuntimeException("monkey"); diff --git a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java b/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java index 4cb9794a0ad..efa78c82ee8 100644 --- a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java +++ b/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java @@ -76,6 +76,7 @@ public void monitor_success() throws Exception { assertThat(future.isDone()).isFalse(); verify(monitor).ready(); verify(monitor).requested(); + verify(monitor).dependenciesRequested(); verify(monitor).addCallbackTo(anyListenableFuture()); verify(monitor).methodStarting(); verify(monitor).methodFinished(); @@ -94,6 +95,7 @@ public void monitor_failure() throws Exception { assertThat(future.isDone()).isFalse(); verify(monitor).ready(); verify(monitor).requested(); + verify(monitor).dependenciesRequested(); verify(monitor).addCallbackTo(anyListenableFuture()); verify(monitor).methodStarting(); verify(monitor).methodFinished(); diff --git a/javatests/dagger/producers/monitoring/internal/MonitorsTest.java b/javatests/dagger/producers/monitoring/internal/MonitorsTest.java index ada4e335b0d..efc21b1836b 100644 --- a/javatests/dagger/producers/monitoring/internal/MonitorsTest.java +++ b/javatests/dagger/producers/monitoring/internal/MonitorsTest.java @@ -124,12 +124,14 @@ public void singleMonitor_normalProducerMonitorSuccess() { monitor.producerMonitorFor(ProducerToken.create(Object.class)); Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); InOrder order = inOrder(mockProducerMonitor); order.verify(mockProducerMonitor).requested(); + order.verify(mockProducerMonitor).dependenciesRequested(); order.verify(mockProducerMonitor).methodStarting(); order.verify(mockProducerMonitor).methodFinished(); order.verify(mockProducerMonitor).succeeded(o); @@ -147,12 +149,14 @@ public void singleMonitor_normalProducerMonitorFailure() { monitor.producerMonitorFor(ProducerToken.create(Object.class)); Throwable t = new RuntimeException("monkey"); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.failed(t); InOrder order = inOrder(mockProducerMonitor); order.verify(mockProducerMonitor).requested(); + order.verify(mockProducerMonitor).dependenciesRequested(); order.verify(mockProducerMonitor).methodStarting(); order.verify(mockProducerMonitor).methodFinished(); order.verify(mockProducerMonitor).failed(t); @@ -163,6 +167,7 @@ public void singleMonitor_normalProducerMonitorFailure() { public void singleMonitor_throwingProducerMonitorSuccess() { setUpNormalSingleMonitor(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).requested(); + doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).dependenciesRequested(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodStarting(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodFinished(); doThrow(new RuntimeException("monkey")) @@ -176,12 +181,14 @@ public void singleMonitor_throwingProducerMonitorSuccess() { monitor.producerMonitorFor(ProducerToken.create(Object.class)); Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); InOrder order = inOrder(mockProducerMonitor); order.verify(mockProducerMonitor).requested(); + order.verify(mockProducerMonitor).dependenciesRequested(); order.verify(mockProducerMonitor).methodStarting(); order.verify(mockProducerMonitor).methodFinished(); order.verify(mockProducerMonitor).succeeded(o); @@ -192,6 +199,7 @@ public void singleMonitor_throwingProducerMonitorSuccess() { public void singleMonitor_throwingProducerMonitorFailure() { setUpNormalSingleMonitor(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).requested(); + doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).dependenciesRequested(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodStarting(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodFinished(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).failed(any(Throwable.class)); @@ -203,12 +211,14 @@ public void singleMonitor_throwingProducerMonitorFailure() { monitor.producerMonitorFor(ProducerToken.create(Object.class)); Throwable t = new RuntimeException("gorilla"); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.failed(t); InOrder order = inOrder(mockProducerMonitor); order.verify(mockProducerMonitor).requested(); + order.verify(mockProducerMonitor).dependenciesRequested(); order.verify(mockProducerMonitor).methodStarting(); order.verify(mockProducerMonitor).methodFinished(); order.verify(mockProducerMonitor).failed(t); @@ -269,12 +279,14 @@ public void multipleMonitors_someNullProductionComponentMonitors() { Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); InOrder order = inOrder(mockProducerMonitorA); order.verify(mockProducerMonitorA).requested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorA).methodFinished(); order.verify(mockProducerMonitorA).succeeded(o); @@ -305,12 +317,14 @@ public void multipleMonitors_someThrowingProductionComponentMonitorFactories() { Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); InOrder order = inOrder(mockProducerMonitorA); order.verify(mockProducerMonitorA).requested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorA).methodFinished(); order.verify(mockProducerMonitorA).succeeded(o); @@ -332,6 +346,7 @@ public void multipleMonitors_normalProductionComponentMonitorSuccess() { Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); @@ -340,6 +355,9 @@ public void multipleMonitors_normalProductionComponentMonitorSuccess() { order.verify(mockProducerMonitorA).requested(); order.verify(mockProducerMonitorB).requested(); order.verify(mockProducerMonitorC).requested(); + order.verify(mockProducerMonitorC).dependenciesRequested(); + order.verify(mockProducerMonitorB).dependenciesRequested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorB).methodStarting(); order.verify(mockProducerMonitorC).methodStarting(); @@ -367,6 +385,7 @@ public void multipleMonitors_normalProductionComponentMonitorFailure() { Throwable t = new RuntimeException("chimpanzee"); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.failed(t); @@ -375,6 +394,9 @@ public void multipleMonitors_normalProductionComponentMonitorFailure() { order.verify(mockProducerMonitorA).requested(); order.verify(mockProducerMonitorB).requested(); order.verify(mockProducerMonitorC).requested(); + order.verify(mockProducerMonitorC).dependenciesRequested(); + order.verify(mockProducerMonitorB).dependenciesRequested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorB).methodStarting(); order.verify(mockProducerMonitorC).methodStarting(); @@ -391,6 +413,7 @@ public void multipleMonitors_normalProductionComponentMonitorFailure() { public void multipleMonitors_someThrowingProducerMonitorsSuccess() { setUpNormalMultipleMonitors(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).requested(); + doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).dependenciesRequested(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).methodStarting(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorB).methodFinished(); doThrow(new RuntimeException("monkey")) @@ -408,6 +431,7 @@ public void multipleMonitors_someThrowingProducerMonitorsSuccess() { Object o = new Object(); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.succeeded(o); @@ -416,6 +440,9 @@ public void multipleMonitors_someThrowingProducerMonitorsSuccess() { order.verify(mockProducerMonitorA).requested(); order.verify(mockProducerMonitorB).requested(); order.verify(mockProducerMonitorC).requested(); + order.verify(mockProducerMonitorC).dependenciesRequested(); + order.verify(mockProducerMonitorB).dependenciesRequested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorB).methodStarting(); order.verify(mockProducerMonitorC).methodStarting(); @@ -432,6 +459,7 @@ public void multipleMonitors_someThrowingProducerMonitorsSuccess() { public void multipleMonitors_someThrowingProducerMonitorsFailure() { setUpNormalMultipleMonitors(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).requested(); + doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).dependenciesRequested(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).methodStarting(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorB).methodFinished(); doThrow(new RuntimeException("monkey")).when(mockProducerMonitorC).failed(any(Throwable.class)); @@ -447,6 +475,7 @@ public void multipleMonitors_someThrowingProducerMonitorsFailure() { Throwable t = new RuntimeException("chimpanzee"); producerMonitor.requested(); + producerMonitor.dependenciesRequested(); producerMonitor.methodStarting(); producerMonitor.methodFinished(); producerMonitor.failed(t); @@ -455,6 +484,9 @@ public void multipleMonitors_someThrowingProducerMonitorsFailure() { order.verify(mockProducerMonitorA).requested(); order.verify(mockProducerMonitorB).requested(); order.verify(mockProducerMonitorC).requested(); + order.verify(mockProducerMonitorC).dependenciesRequested(); + order.verify(mockProducerMonitorB).dependenciesRequested(); + order.verify(mockProducerMonitorA).dependenciesRequested(); order.verify(mockProducerMonitorA).methodStarting(); order.verify(mockProducerMonitorB).methodStarting(); order.verify(mockProducerMonitorC).methodStarting();