.NET Purview Middleware: Improve Background Job Runner Injection (#3256)

* Clean up background job dependency injection

* Fix xml documentation grammar
This commit is contained in:
eoindoherty1
2026-01-16 11:20:35 -08:00
committed by GitHub
Unverified
parent b773830e4b
commit a151f10cc2
5 changed files with 36 additions and 12 deletions
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Purview;
/// <summary>
/// Service that runs jobs in background threads.
/// </summary>
internal sealed class BackgroundJobRunner
internal sealed class BackgroundJobRunner : IBackgroundJobRunner
{
private readonly IChannelHandler _channelHandler;
private readonly IPurviewClient _purviewClient;
@@ -70,4 +70,12 @@ internal sealed class BackgroundJobRunner
break;
}
}
/// <summary>
/// Shutdown the job runners.
/// </summary>
public async Task ShutdownAsync()
{
await this._channelHandler.StopAndWaitForCompletionAsync().ConfigureAwait(false);
}
}
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Threading.Tasks;
namespace Microsoft.Agents.AI.Purview;
/// <summary>
/// An interface for a class that manages background jobs.
/// </summary>
internal interface IBackgroundJobRunner
{
/// <summary>
/// Shutdown the background jobs.
/// </summary>
Task ShutdownAsync();
}
@@ -41,7 +41,7 @@ public static class PurviewExtensions
services.AddSingleton<PurviewWrapper>();
services.AddSingleton(Channel.CreateBounded<BackgroundJobBase>(purviewSettings.PendingBackgroundJobLimit));
services.AddSingleton<IChannelHandler, ChannelHandler>();
services.AddSingleton<BackgroundJobRunner>();
services.AddSingleton<IBackgroundJobRunner, BackgroundJobRunner>();
ServiceProvider serviceProvider = services.BuildServiceProvider();
return serviceProvider.GetRequiredService<PurviewWrapper>();
@@ -18,7 +18,7 @@ internal sealed class PurviewWrapper : IDisposable
private readonly ILogger _logger;
private readonly IScopedContentProcessor _scopedProcessor;
private readonly PurviewSettings _purviewSettings;
private readonly IChannelHandler _channelHandler;
private readonly IBackgroundJobRunner _backgroundJobRunner;
/// <summary>
/// Creates a new <see cref="PurviewWrapper"/> instance.
@@ -26,13 +26,13 @@ internal sealed class PurviewWrapper : IDisposable
/// <param name="scopedProcessor">The scoped processor used to orchestrate the calls to Purview.</param>
/// <param name="purviewSettings">The settings for Purview integration.</param>
/// <param name="logger">The logger used for logging.</param>
/// <param name="channelHandler">The channel handler used to queue background jobs and add job runners.</param>
public PurviewWrapper(IScopedContentProcessor scopedProcessor, PurviewSettings purviewSettings, ILogger logger, IChannelHandler channelHandler)
/// <param name="backgroundJobRunner">The runner used to manage background jobs.</param>
public PurviewWrapper(IScopedContentProcessor scopedProcessor, PurviewSettings purviewSettings, ILogger logger, IBackgroundJobRunner backgroundJobRunner)
{
this._scopedProcessor = scopedProcessor;
this._purviewSettings = purviewSettings;
this._logger = logger;
this._channelHandler = channelHandler;
this._backgroundJobRunner = backgroundJobRunner;
}
private static string GetThreadIdFromAgentThread(AgentThread? thread, IEnumerable<ChatMessage> messages)
@@ -203,7 +203,7 @@ internal sealed class PurviewWrapper : IDisposable
public void Dispose()
{
#pragma warning disable VSTHRD002 // Need to wait for pending jobs to complete.
this._channelHandler.StopAndWaitForCompletionAsync().GetAwaiter().GetResult();
this._backgroundJobRunner.ShutdownAsync().GetAwaiter().GetResult();
#pragma warning restore VSTHRD002 // Need to wait for pending jobs to complete.
}
}
@@ -18,14 +18,13 @@ namespace Microsoft.Agents.AI.Purview.UnitTests;
public sealed class PurviewWrapperTests : IDisposable
{
private readonly Mock<IScopedContentProcessor> _mockProcessor;
private readonly IChannelHandler _channelHandler;
private readonly IBackgroundJobRunner _backgroundJobRunner;
private readonly PurviewSettings _settings;
private readonly PurviewWrapper _wrapper;
public PurviewWrapperTests()
{
this._mockProcessor = new Mock<IScopedContentProcessor>();
this._channelHandler = Mock.Of<IChannelHandler>();
this._settings = new PurviewSettings("TestApp")
{
TenantId = "tenant-123",
@@ -33,7 +32,8 @@ public sealed class PurviewWrapperTests : IDisposable
BlockedPromptMessage = "Prompt blocked by policy",
BlockedResponseMessage = "Response blocked by policy"
};
this._wrapper = new PurviewWrapper(this._mockProcessor.Object, this._settings, NullLogger.Instance, this._channelHandler);
this._backgroundJobRunner = Mock.Of<IBackgroundJobRunner>();
this._wrapper = new PurviewWrapper(this._mockProcessor.Object, this._settings, NullLogger.Instance, this._backgroundJobRunner);
}
#region ProcessChatContentAsync Tests
@@ -151,7 +151,7 @@ public sealed class PurviewWrapperTests : IDisposable
IgnoreExceptions = true,
PurviewAppLocation = new PurviewAppLocation(PurviewLocationType.Application, "app-123")
};
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._channelHandler);
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._backgroundJobRunner);
var messages = new List<ChatMessage>
{
@@ -371,7 +371,7 @@ public sealed class PurviewWrapperTests : IDisposable
IgnoreExceptions = true,
PurviewAppLocation = new PurviewAppLocation(PurviewLocationType.Application, "app-123")
};
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._channelHandler);
var wrapper = new PurviewWrapper(this._mockProcessor.Object, settingsWithIgnore, NullLogger.Instance, this._backgroundJobRunner);
var messages = new List<ChatMessage>
{