-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor service lifetimes and improve TranslationService testability #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -116,20 +116,20 @@ | |||||
| builder.Services.Configure<ApiSettings>(builder.Configuration.GetSection("ApiSettings")); | ||||||
|
|
||||||
| // Register core services | ||||||
| builder.Services.AddScoped<ITranslationService, TranslationService>(); | ||||||
| builder.Services.AddScoped<ILyricsService, LyricsService>(); | ||||||
| builder.Services.AddSingleton<ITranslationService, TranslationService>(); | ||||||
| builder.Services.AddSingleton<ILyricsService, LyricsService>(); | ||||||
|
|
||||||
| // Register validation services | ||||||
| builder.Services.AddSingleton<ISpeechConfigValidator, SpeechConfigValidator>(); | ||||||
| builder.Services.AddScoped<IAudioSynthesisService, AudioSynthesisService>(); | ||||||
| builder.Services.AddSingleton<IAudioSynthesisService, AudioSynthesisService>(); | ||||||
|
||||||
| builder.Services.AddSingleton<IAudioSynthesisService, AudioSynthesisService>(); | |
| builder.Services.AddScoped<IAudioSynthesisService, AudioSynthesisService>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple implementations of IDiagnosticValidator are registered as singletons:
builder.Services.AddSingleton<IDiagnosticValidator, AzureOpenAIDiagnosticValidator>();
builder.Services.AddSingleton<IDiagnosticValidator, AzureSpeechDiagnosticValidator>();
builder.Services.AddSingleton<IDiagnosticValidator, InternetConnectivityDiagnosticValidator>();If these are intended to be injected as a collection (e.g., IEnumerable<IDiagnosticValidator>), this is correct. However, if a single instance is expected, this will cause ambiguity and may result in only the last registration being resolved. Ensure that the consuming code expects a collection, or clarify the registration strategy.
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Converting services to Singleton while using IOptions means configuration values will be captured once at application startup and never refreshed. If runtime configuration reloading is needed in the future, these services would need to use IOptionsMonitor instead. This is acceptable if configuration is static for the application lifetime, which appears to be the current design (no reloadOnChange detected in configuration setup).
| builder.Services.AddSingleton<IDiagnosticService, DiagnosticService>(); | |
| builder.Services.AddScoped<IDiagnosticService, DiagnosticService>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All services in this range are registered as singletons. If any of these services depend on scoped or transient services, this can lead to data races or unintended shared state across requests. Review the constructors of these services to ensure that singleton lifetime is appropriate and does not introduce thread safety or resource contention issues. If any service requires per-request or per-operation state, consider using scoped or transient lifetimes instead.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| using Azure.AI.OpenAI; | ||
| using Microsoft.ApplicationInsights; | ||
| using Microsoft.ApplicationInsights.DataContracts; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Options; | ||
| using OpenAI.Chat; | ||
| using PoVicTranslate.Web.Configuration; | ||
|
|
@@ -27,10 +28,20 @@ Maintain the sentiment and intent of the original text. | |
| Do not add any explanations, only provide the translated text. | ||
| """; | ||
|
|
||
| [ActivatorUtilitiesConstructor] | ||
| public TranslationService( | ||
| IOptions<ApiSettings> apiSettings, | ||
| TelemetryClient telemetryClient, | ||
| ILogger<TranslationService> logger) | ||
| : this(apiSettings, telemetryClient, logger, null) | ||
| { | ||
| } | ||
|
|
||
| public TranslationService( | ||
| IOptions<ApiSettings> apiSettings, | ||
| TelemetryClient telemetryClient, | ||
| ILogger<TranslationService> logger, | ||
| ChatClient? chatClient) | ||
|
Comment on lines
+40
to
+44
|
||
| { | ||
| ArgumentNullException.ThrowIfNull(apiSettings); | ||
| _telemetryClient = telemetryClient; | ||
|
Comment on lines
+41
to
47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The constructor does not validate that Recommendation: ArgumentNullException.ThrowIfNull(telemetryClient);
ArgumentNullException.ThrowIfNull(logger);Insert these checks before assigning the fields. |
||
|
|
@@ -39,6 +50,13 @@ public TranslationService( | |
| var settings = apiSettings.Value; | ||
| _deploymentName = settings.AzureOpenAIDeploymentName; | ||
|
|
||
| if (chatClient is not null) | ||
| { | ||
| _chatClient = chatClient; | ||
| _logger.LogInformation("TranslationService initialized with injected ChatClient"); | ||
| return; | ||
| } | ||
|
|
||
| if (string.IsNullOrWhiteSpace(settings.AzureOpenAIApiKey) || | ||
| string.IsNullOrWhiteSpace(settings.AzureOpenAIEndpoint) || | ||
| string.IsNullOrWhiteSpace(settings.AzureOpenAIDeploymentName)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SDK version is being downgraded from 10.0.102 to 10.0.100. While the PR description states this matches the available SDK, this change should be verified to ensure 10.0.102 was not actually available or required. If this is a temporary workaround for local development, consider documenting why 10.0.100 is required or whether this could cause issues for other developers or CI/CD pipelines expecting 10.0.102.