Skip to content

Commit 8893a4c

Browse files
Copilotjongalloway
andcommitted
Implement multi-backend retrieval architecture with comprehensive tests
Co-authored-by: jongalloway <[email protected]>
1 parent 16c296e commit 8893a4c

File tree

9 files changed

+869
-5
lines changed

9 files changed

+869
-5
lines changed

src/NLWebNet/Extensions/ServiceCollectionExtensions.cs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using Microsoft.Extensions.DependencyInjection;
22
using Microsoft.Extensions.Diagnostics.HealthChecks;
3+
using Microsoft.Extensions.AI;
4+
using Microsoft.Extensions.Logging;
5+
using Microsoft.Extensions.Options;
36
using NLWebNet.Models;
47
using NLWebNet.Services;
58
using NLWebNet.MCP;
@@ -94,4 +97,104 @@ public static IServiceCollection AddNLWebNet<TDataBackend>(this IServiceCollecti
9497

9598
return services;
9699
}
100+
101+
/// <summary>
102+
/// Adds NLWebNet services with multi-backend support
103+
/// </summary>
104+
/// <param name="services">The service collection</param>
105+
/// <param name="configureOptions">Optional configuration callback</param>
106+
/// <param name="configureMultiBackend">Multi-backend configuration callback</param>
107+
/// <returns>The service collection for chaining</returns>
108+
public static IServiceCollection AddNLWebNetMultiBackend(this IServiceCollection services,
109+
Action<NLWebOptions>? configureOptions = null,
110+
Action<MultiBackendOptions>? configureMultiBackend = null)
111+
{
112+
// Configure options
113+
if (configureOptions != null)
114+
{
115+
services.Configure(configureOptions);
116+
}
117+
118+
// Configure multi-backend options
119+
if (configureMultiBackend != null)
120+
{
121+
services.Configure<MultiBackendOptions>(configureMultiBackend);
122+
}
123+
124+
// Add logging (required for the services)
125+
services.AddLogging();
126+
127+
// Register core NLWebNet services
128+
services.AddScoped<INLWebService>(provider =>
129+
{
130+
var options = provider.GetRequiredService<IOptions<NLWebOptions>>();
131+
if (options.Value.MultiBackend.Enabled)
132+
{
133+
// Use multi-backend constructor
134+
return new NLWebService(
135+
provider.GetRequiredService<IQueryProcessor>(),
136+
provider.GetRequiredService<IResultGenerator>(),
137+
provider.GetRequiredService<IBackendManager>(),
138+
provider.GetRequiredService<ILogger<NLWebService>>(),
139+
options);
140+
}
141+
else
142+
{
143+
// Use single backend constructor for backward compatibility
144+
return new NLWebService(
145+
provider.GetRequiredService<IQueryProcessor>(),
146+
provider.GetRequiredService<IResultGenerator>(),
147+
provider.GetRequiredService<IDataBackend>(),
148+
provider.GetRequiredService<ILogger<NLWebService>>(),
149+
options);
150+
}
151+
});
152+
153+
services.AddScoped<IQueryProcessor, QueryProcessor>();
154+
services.AddScoped<IResultGenerator>(provider =>
155+
{
156+
var options = provider.GetRequiredService<IOptions<NLWebOptions>>();
157+
if (options.Value.MultiBackend.Enabled)
158+
{
159+
// Use multi-backend constructor
160+
return new ResultGenerator(
161+
provider.GetRequiredService<IBackendManager>(),
162+
provider.GetRequiredService<ILogger<ResultGenerator>>(),
163+
options,
164+
provider.GetService<IChatClient>());
165+
}
166+
else
167+
{
168+
// Use single backend constructor for backward compatibility
169+
return new ResultGenerator(
170+
provider.GetRequiredService<IDataBackend>(),
171+
provider.GetRequiredService<ILogger<ResultGenerator>>(),
172+
options,
173+
provider.GetService<IChatClient>());
174+
}
175+
});
176+
177+
// Register MCP services
178+
services.AddScoped<IMcpService, McpService>();
179+
180+
// Register multi-backend services
181+
services.AddScoped<IBackendManager, BackendManager>();
182+
183+
// Register default data backend (can be overridden)
184+
services.AddScoped<IDataBackend, MockDataBackend>();
185+
186+
// Add health checks
187+
services.AddHealthChecks()
188+
.AddCheck<NLWebHealthCheck>("nlweb")
189+
.AddCheck<DataBackendHealthCheck>("data-backend")
190+
.AddCheck<AIServiceHealthCheck>("ai-service");
191+
192+
// Add metrics
193+
services.AddMetrics();
194+
195+
// Add rate limiting
196+
services.AddSingleton<IRateLimitingService, InMemoryRateLimitingService>();
197+
198+
return services;
199+
}
97200
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace NLWebNet.Models;
4+
5+
/// <summary>
6+
/// Configuration options for multi-backend retrieval architecture.
7+
/// </summary>
8+
public class MultiBackendOptions
9+
{
10+
/// <summary>
11+
/// The configuration section name for binding from appsettings.json.
12+
/// </summary>
13+
public const string SectionName = "NLWebNet:MultiBackend";
14+
15+
/// <summary>
16+
/// Whether multi-backend mode is enabled. When false, uses single backend for backward compatibility.
17+
/// </summary>
18+
public bool Enabled { get; set; } = false;
19+
20+
/// <summary>
21+
/// The identifier of the backend to use as the primary write endpoint.
22+
/// </summary>
23+
public string? WriteEndpoint { get; set; }
24+
25+
/// <summary>
26+
/// Configuration for individual backend endpoints.
27+
/// </summary>
28+
public Dictionary<string, BackendEndpointOptions> Endpoints { get; set; } = new();
29+
30+
/// <summary>
31+
/// Whether to enable parallel querying across backends.
32+
/// </summary>
33+
public bool EnableParallelQuerying { get; set; } = true;
34+
35+
/// <summary>
36+
/// Whether to enable automatic result deduplication.
37+
/// </summary>
38+
public bool EnableResultDeduplication { get; set; } = true;
39+
40+
/// <summary>
41+
/// Maximum number of concurrent backend queries.
42+
/// </summary>
43+
[Range(1, 10)]
44+
public int MaxConcurrentQueries { get; set; } = 5;
45+
46+
/// <summary>
47+
/// Timeout for individual backend queries in seconds.
48+
/// </summary>
49+
[Range(1, 120)]
50+
public int BackendTimeoutSeconds { get; set; } = 30;
51+
}
52+
53+
/// <summary>
54+
/// Configuration for an individual backend endpoint.
55+
/// </summary>
56+
public class BackendEndpointOptions
57+
{
58+
/// <summary>
59+
/// Whether this backend endpoint is enabled.
60+
/// </summary>
61+
public bool Enabled { get; set; } = true;
62+
63+
/// <summary>
64+
/// The type of backend (e.g., "azure_ai_search", "mock", "custom").
65+
/// </summary>
66+
public string BackendType { get; set; } = string.Empty;
67+
68+
/// <summary>
69+
/// Priority for this backend (higher values = higher priority).
70+
/// Used for ordering results when deduplication is disabled.
71+
/// </summary>
72+
public int Priority { get; set; } = 0;
73+
74+
/// <summary>
75+
/// Backend-specific configuration properties.
76+
/// </summary>
77+
public Dictionary<string, object> Properties { get; set; } = new();
78+
}

src/NLWebNet/Models/NLWebOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,9 @@ public class NLWebOptions
7171
/// Rate limiting configuration
7272
/// </summary>
7373
public RateLimitingOptions RateLimiting { get; set; } = new();
74+
75+
/// <summary>
76+
/// Multi-backend configuration options. When enabled, overrides single backend behavior.
77+
/// </summary>
78+
public MultiBackendOptions MultiBackend { get; set; } = new();
7479
}

0 commit comments

Comments
 (0)