diff --git a/docs/events/projections/async-daemon.md b/docs/events/projections/async-daemon.md
index 40773d8f72..fe37a3781c 100644
--- a/docs/events/projections/async-daemon.md
+++ b/docs/events/projections/async-daemon.md
@@ -237,6 +237,37 @@ The basic idea in your tests is to:
There is also another overload to wait for just one tenant database in the case of using a database per tenant. The default
overload **will wait for the daemon of all known databases to catch up to the latest sequence.**
+### Accessing the daemon from IHost:
+
+If you're integration testing with the `IHost` (e.g. using Alba) object, you can access the daemon and wait for non stale data like this:
+
+
+
+```cs
+[Fact]
+public async Task run_simultaneously()
+{
+ var host = await StartDaemonInHotColdMode();
+
+ StoreOptions(x => x.Projections.Add(new DistanceProjection(), ProjectionLifecycle.Async));
+
+ NumberOfStreams = 10;
+
+ var agent = await StartDaemon();
+
+ // This method publishes a random number of events
+ await PublishSingleThreaded();
+
+ // Wait for all projections to reach the highest event sequence point
+ // as of the time this method is called
+ await host.WaitForNonStaleProjectionDataAsync(15.Seconds());
+
+ await CheckExpectedResults();
+}
+```
+snippet source | anchor
+
+
## Diagnostics
The following code shows the diagnostics support for the async daemon as it is today:
diff --git a/src/DaemonTests/event_projections_end_to_end_ihost.cs b/src/DaemonTests/event_projections_end_to_end_ihost.cs
new file mode 100644
index 0000000000..d72a4ed8a2
--- /dev/null
+++ b/src/DaemonTests/event_projections_end_to_end_ihost.cs
@@ -0,0 +1,88 @@
+using System.Linq;
+using System.Threading.Tasks;
+using DaemonTests.TestingSupport;
+using JasperFx.Core;
+using Marten;
+using Marten.Events;
+using Marten.Events.Projections;
+using Microsoft.Extensions.Logging;
+using Shouldly;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace DaemonTests;
+
+public class event_projections_end_to_end_ihost : DaemonContext
+{
+ public event_projections_end_to_end_ihost(ITestOutputHelper output) : base(output)
+ {
+ _output = output;
+ }
+
+ #region sample_accessing_daemon_from_ihost
+
+ [Fact]
+ public async Task run_simultaneously()
+ {
+ var host = await StartDaemonInHotColdMode();
+
+ StoreOptions(x => x.Projections.Add(new DistanceProjection(), ProjectionLifecycle.Async));
+
+ NumberOfStreams = 10;
+
+ var agent = await StartDaemon();
+
+ // This method publishes a random number of events
+ await PublishSingleThreaded();
+
+ // Wait for all projections to reach the highest event sequence point
+ // as of the time this method is called
+ await host.WaitForNonStaleProjectionDataAsync(15.Seconds());
+
+ await CheckExpectedResults();
+ }
+
+ #endregion
+
+ private Task CheckExpectedResults()
+ {
+ return CheckExpectedResults(theSession);
+ }
+
+ private async Task CheckExpectedResultsForTenants(params string[] tenants)
+ {
+ foreach (var tenantId in tenants)
+ {
+ await using (var session = theStore.LightweightSession(tenantId))
+ {
+ await CheckExpectedResults(session);
+ }
+ }
+ }
+
+
+
+ private async Task CheckExpectedResults(IDocumentSession session)
+ {
+ var distances = await session.Query().ToListAsync();
+
+ var events = (await session.Events.QueryAllRawEvents().ToListAsync());
+ var travels = events.OfType>().ToDictionary(x => x.Id);
+
+ distances.Count.ShouldBe(travels.Count);
+ foreach (var distance in distances)
+ {
+ if (travels.TryGetValue(distance.Id, out var travel))
+ {
+ distance.Day.ShouldBe(travel.Data.Day);
+ distance.Total.ShouldBe(travel.Data.TotalDistance());
+ }
+ else
+ {
+ travel.ShouldNotBeNull();
+ }
+
+ Logger.LogDebug("Compared distance " + distance);
+ }
+ }
+}