Skip to content

Commit b527210

Browse files
author
yuqingyang
committed
Add polly policy for mail repo
Clean up AADReader code Clean up Notifier code Clean up Notifier code2 Add retry logic Add retry logic in Mail.Repo Fix rebase typo Add test for mail repo Add policy test Add config value Add falied notification queue Send queue message if failed Correct template Correct the respone code Clean up code and add null check
1 parent b463834 commit b527210

File tree

22 files changed

+569
-210
lines changed

22 files changed

+569
-210
lines changed

Infrastructure/data/template.bicep

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ param serviceBusMembershipAggregatorQueue string = 'membershipAggregator'
101101
@description('Enter notifications service bus queue name')
102102
param serviceBusNotificationsQueue string = 'notifications'
103103

104+
@description('Enter notifications service bus queue name')
105+
param serviceBusFailedNotificationsQueue string = 'failedNotifications'
106+
104107
@description('Enter storage account name.')
105108
@minLength(1)
106109
@maxLength(24)
@@ -184,6 +187,22 @@ param appConfigurationKeyData array = [
184187
tag1: 'JobTrigger'
185188
}
186189
}
190+
{
191+
key: 'MaxExceptionHandlingAttempts'
192+
value: '2'
193+
contentType: 'integer'
194+
tag: {
195+
tag1: 'RetryPolicy'
196+
}
197+
}
198+
{
199+
key: 'MaxRetryAfterAttempts'
200+
value: '4'
201+
contentType: 'integer'
202+
tag: {
203+
tag1: 'RetryPolicy'
204+
}
205+
}
187206
{
188207
key: 'GroupMembershipObtainer:IsDeltaCacheEnabled'
189208
value: 'false'
@@ -497,6 +516,19 @@ module notificationsQueue 'serviceBusQueue.bicep' = {
497516
]
498517
}
499518

519+
module failedNotificationsQueue 'serviceBusQueue.bicep' = {
520+
name: 'failedNotificationsQueue'
521+
params: {
522+
queueName: serviceBusFailedNotificationsQueue
523+
serviceBusName: serviceBusName
524+
requiresSession: false
525+
maxDeliveryCount: 5
526+
}
527+
dependsOn:[
528+
serviceBusTemplate
529+
]
530+
}
531+
500532
module storageAccountTemplate 'storageAccount.bicep' = {
501533
name: 'storageAccountTemplate'
502534
params: {
@@ -638,6 +670,10 @@ module secretsTemplate 'keyVaultSecrets.bicep' = {
638670
name: 'serviceBusNotificationsQueue'
639671
value: serviceBusNotificationsQueue
640672
}
673+
{
674+
name: 'serviceBusFailedNotificationsQueue'
675+
value: serviceBusFailedNotificationsQueue
676+
}
641677
{
642678
name: 'graphUserAssignedManagedIdentityName'
643679
value: graphUserAssignedManagedIdentityName

Service/GroupMembershipManagement/GroupMembershipManagement.sln

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repositories.EntityFramewor
6161
EndProject
6262
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repositories.FeatureFlag", "Repositories.FeatureFlag\Repositories.FeatureFlag.csproj", "{694A5629-D09B-4855-93E1-96D6DE6D07F3}"
6363
EndProject
64-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repositories.Contracts.Tests", "Repositories.Contracts.Tests\Repositories.Contracts.Tests.csproj", "{36E351DC-46F2-40FE-9F07-D15334B99AC1}"
64+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repositories.Contracts.Tests", "Repositories.Contracts.Tests\Repositories.Contracts.Tests.csproj", "{36E351DC-46F2-40FE-9F07-D15334B99AC1}"
65+
EndProject
66+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repositories.RetryPolicyProvider", "Repositories.RetryPolicyProvider\Repositories.RetryPolicyProvider.csproj", "{1536370F-54D6-4325-B212-8AC535357DDF}"
6567
EndProject
6668
Global
6769
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -181,6 +183,10 @@ Global
181183
{36E351DC-46F2-40FE-9F07-D15334B99AC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
182184
{36E351DC-46F2-40FE-9F07-D15334B99AC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
183185
{36E351DC-46F2-40FE-9F07-D15334B99AC1}.Release|Any CPU.Build.0 = Release|Any CPU
186+
{1536370F-54D6-4325-B212-8AC535357DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
187+
{1536370F-54D6-4325-B212-8AC535357DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
188+
{1536370F-54D6-4325-B212-8AC535357DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
189+
{1536370F-54D6-4325-B212-8AC535357DDF}.Release|Any CPU.Build.0 = Release|Any CPU
184190
EndGlobalSection
185191
GlobalSection(SolutionProperties) = preSolution
186192
HideSolutionNode = FALSE

Service/GroupMembershipManagement/Hosts.FunctionBase/CommonStartup.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Repositories.Logging;
1919
using Repositories.Mail;
2020
using Repositories.NotificationsRepository;
21+
using Repositories.RetryPolicyProvider;
2122
using System;
2223
using System.Collections.Generic;
2324
using System.Globalization;
@@ -100,18 +101,34 @@ public override void Configure(IFunctionsHostBuilder builder)
100101
ServiceLifetime.Scoped
101102
);
102103

104+
builder.Services.AddOptions<GraphServiceAttemptsValue>().Configure<IConfiguration>((settings, configuration) =>
105+
{
106+
settings.MaxRetryAfterAttempts = GetIntSetting(configuration, "MaxRetryAfterAttempts", 4);
107+
settings.MaxExceptionHandlingAttempts = GetIntSetting(configuration, "MaxExceptionHandlingAttempts", 2);
108+
});
109+
110+
builder.Services.AddSingleton<IGraphServiceAttemptsValue>(services =>
111+
{
112+
var options = services.GetRequiredService<IOptions<GraphServiceAttemptsValue>>();
113+
return new GraphServiceAttemptsValue
114+
{
115+
MaxRetryAfterAttempts = options.Value.MaxRetryAfterAttempts,
116+
MaxExceptionHandlingAttempts = options.Value.MaxExceptionHandlingAttempts
117+
};
118+
});
119+
120+
builder.Services.AddSingleton<ILoggingRepository, LoggingRepository>();
103121
builder.Services.AddScoped<IDatabaseSyncJobsRepository, DatabaseSyncJobsRepository>();
104122
builder.Services.AddScoped<IDatabaseSettingsRepository, DatabaseSettingsRepository>();
105123
builder.Services.AddScoped<IDatabaseDestinationAttributesRepository, DatabaseDestinationAttributesRespository>();
106124
builder.Services.AddScoped<INotificationTypesRepository, NotificationTypesRepository>();
107125
builder.Services.AddScoped<IJobNotificationsRepository, JobNotificationRepository>();
108-
126+
builder.Services.AddScoped<IRetryPolicyProvider, RetryPolicyProvider>();
109127
builder.Services.AddSingleton<IAppConfigVerbosity>(services =>
110128
{
111129
var creds = services.GetService<IOptions<AppConfigVerbosity>>();
112130
return new AppConfigVerbosity(creds.Value.Verbosity);
113131
});
114-
builder.Services.AddSingleton<ILoggingRepository, LoggingRepository>();
115132

116133
builder.Services.AddOptions<GMMResources>().Configure<IConfiguration>((settings, configuration) =>
117134
{
@@ -188,7 +205,9 @@ public override void Configure(IFunctionsHostBuilder builder)
188205
services.GetService<ILoggingRepository>(),
189206
GetValueOrDefault("actionableEmailProviderId"),
190207
services.GetService<IGraphGroupRepository>(),
191-
services.GetService<IDatabaseSettingsRepository>());
208+
services.GetService<IDatabaseSettingsRepository>(),
209+
services.GetService<IRetryPolicyProvider>()
210+
);
192211
});
193212

194213
builder.Services.AddOptions<NotificationRepoCredentials<NotificationRepository>>().Configure<IConfiguration>((settings, configuration) =>
@@ -242,5 +261,10 @@ public string GetValueOrDefault(string key, [CallerFilePath] string callerFile =
242261
{
243262
return Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.Process) ?? string.Empty;
244263
}
264+
private int GetIntSetting(IConfiguration configuration, string settingName, int defaultValue)
265+
{
266+
var checkParse = int.TryParse(configuration[settingName], out int value);
267+
return checkParse ? value : defaultValue;
268+
}
245269
}
246270
}

Service/GroupMembershipManagement/Hosts.FunctionBase/Hosts.FunctionBase.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<ProjectReference Include="..\Repositories.Mail\Repositories.Mail.csproj" />
3030
<ProjectReference Include="..\Repositories.ServiceBusQueue\Repositories.ServiceBusQueue.csproj" />
3131
<ProjectReference Include="..\Repositories.Notifications\Repositories.NotificationRepository.csproj" />
32+
<ProjectReference Include="..\Repositories.RetryPolicyProvider\Repositories.RetryPolicyProvider.csproj" />
3233
</ItemGroup>
3334

3435
</Project>

Service/GroupMembershipManagement/Hosts/AzureUserReader/Function/Startup.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,6 @@ public override void Configure(IFunctionsHostBuilder builder)
2727

2828
builder.Services.AddGraphAPIClient();
2929

30-
builder.Services.AddSingleton<IGraphServiceAttemptsValue>(services =>
31-
{
32-
var parseMaxRetryAfterAttempts = int.TryParse(GetValueOrThrow("maxRetryAfterAttempts"), out int maxRetryAfterAttempts);
33-
var parseMaxExceptionHandlingAttempts = int.TryParse(GetValueOrThrow("maxExceptionHandlingAttempts"), out int maxExceptionHandlingAttempts);
34-
if (!parseMaxRetryAfterAttempts || !parseMaxExceptionHandlingAttempts)
35-
{
36-
maxRetryAfterAttempts = 4;
37-
maxExceptionHandlingAttempts = 2;
38-
}
39-
40-
return new GraphServiceAttemptsValue(maxRetryAfterAttempts, maxExceptionHandlingAttempts);
41-
});
42-
4330
builder.Services.AddSingleton<IStorageAccountSecret>(services =>
4431
new StorageAccountSecret(GetValueOrThrow("storageAccountConnectionString")));
4532

Service/GroupMembershipManagement/Hosts/AzureUserReader/Infrastructure/compute/template.bicep

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,6 @@ var appSettings = {
123123
logAnalyticsCustomerId: '@Microsoft.KeyVault(SecretUri=${reference(logAnalyticsCustomerId, '2019-09-01').secretUriWithVersion})'
124124
logAnalyticsPrimarySharedKey: '@Microsoft.KeyVault(SecretUri=${reference(logAnalyticsPrimarySharedKey, '2019-09-01').secretUriWithVersion})'
125125
WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT: maximumElasticWorkerCount
126-
maxRetryAfterAttempts: '4'
127-
maxExceptionHandlingAttempts: '2'
128126
appConfigurationEndpoint: appConfigurationEndpoint
129127
'graphCredentials:UserAssignedManagedIdentityClientId': '@Microsoft.KeyVault(SecretUri=${reference(graphUserAssignedManagedIdentityClientId, '2019-09-01').secretUriWithVersion})'
130128
}

Service/GroupMembershipManagement/Hosts/Notifier/Function/Notifier.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SqlMembershipObtainer.Entit
4949
EndProject
5050
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repositories.EntityFramework.Contexts", "..\..\..\Repositories.EntityFramework.Contexts\Repositories.EntityFramework.Contexts.csproj", "{7C059CC4-6093-463B-981F-EF73D73E371A}"
5151
EndProject
52+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repositories.RetryPolicyProvider", "..\..\..\Repositories.RetryPolicyProvider\Repositories.RetryPolicyProvider.csproj", "{214885C9-9189-4399-A0F4-3F87E4F9279B}"
53+
EndProject
5254
Global
5355
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5456
Debug|Any CPU = Debug|Any CPU
@@ -143,6 +145,10 @@ Global
143145
{7C059CC4-6093-463B-981F-EF73D73E371A}.Debug|Any CPU.Build.0 = Debug|Any CPU
144146
{7C059CC4-6093-463B-981F-EF73D73E371A}.Release|Any CPU.ActiveCfg = Release|Any CPU
145147
{7C059CC4-6093-463B-981F-EF73D73E371A}.Release|Any CPU.Build.0 = Release|Any CPU
148+
{214885C9-9189-4399-A0F4-3F87E4F9279B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
149+
{214885C9-9189-4399-A0F4-3F87E4F9279B}.Debug|Any CPU.Build.0 = Debug|Any CPU
150+
{214885C9-9189-4399-A0F4-3F87E4F9279B}.Release|Any CPU.ActiveCfg = Release|Any CPU
151+
{214885C9-9189-4399-A0F4-3F87E4F9279B}.Release|Any CPU.Build.0 = Release|Any CPU
146152
EndGlobalSection
147153
GlobalSection(SolutionProperties) = preSolution
148154
HideSolutionNode = FALSE

Service/GroupMembershipManagement/Hosts/Notifier/Function/Startup.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
3+
using Azure.Messaging.ServiceBus;
34
using Common.DependencyInjection;
45
using DIConcreteTypes;
56
using Hosts.FunctionBase;
@@ -11,6 +12,7 @@
1112
using Repositories.Contracts;
1213
using Repositories.Contracts.InjectConfig;
1314
using Repositories.GraphGroups;
15+
using Repositories.ServiceBusQueue;
1416
using Services.Contracts.Notifications;
1517
using Services.Notifications;
1618
using Services.Notifier;
@@ -73,12 +75,19 @@ public override void Configure(IFunctionsHostBuilder builder)
7375
services.GetService<IOptions<ThresholdConfig>>().Value.NumberOfThresholdViolationsToDisableJob
7476
);
7577
});
78+
builder.Services.AddSingleton<IServiceBusQueueRepository, ServiceBusQueueRepository>(services =>
79+
{
80+
var configuration = services.GetRequiredService<IConfiguration>();
81+
var failedNotificationsQueue = configuration["serviceBusFailedNotificationsQueue"];
82+
var client = services.GetRequiredService<ServiceBusClient>();
83+
var sender = client.CreateSender(failedNotificationsQueue);
84+
return new ServiceBusQueueRepository(sender);
85+
});
7686
builder.Services.AddScoped<IThresholdNotificationConfig>((sp) =>
7787
{
7888
return new ThresholdNotificationConfig(true);
7989
});
8090
builder.Services.AddScoped<IThresholdNotificationService, ThresholdNotificationService>();
81-
8291
builder.Services.AddHttpClient();
8392
}
8493

Service/GroupMembershipManagement/Hosts/Notifier/Infrastructure/compute/template.bicep

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ var replicaJobsMSIConnectionString = resourceId(subscription().subscriptionId, d
116116
var notifierStorageAccountProd = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'notifierStorageAccountProd')
117117
var notifierStorageAccountStaging = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'notifierStorageAccountStaging')
118118
var serviceBusNotificationsQueue = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'serviceBusNotificationsQueue')
119+
var serviceBusFailedNotificationsQueue = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'serviceBusFailedNotificationsQueue')
119120
var serviceBusFQN = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'serviceBusFQN')
120121
var graphUserAssignedManagedIdentityClientId = resourceId(subscription().subscriptionId, dataKeyVaultResourceGroup, 'Microsoft.KeyVault/vaults/secrets', dataKeyVaultName, 'graphUserAssignedManagedIdentityClientId')
121122

@@ -160,6 +161,7 @@ var appSettings = {
160161
actionableEmailProviderId: '@Microsoft.KeyVault(SecretUri=${reference(actionableEmailProviderId, '2019-09-01').secretUriWithVersion})'
161162
apiHostname: apiHostname
162163
serviceBusNotificationsQueue: '@Microsoft.KeyVault(SecretUri=${reference(serviceBusNotificationsQueue, '2019-09-01').secretUriWithVersion})'
164+
serviceBusFailedNotificationsQueue: '@Microsoft.KeyVault(SecretUri=${reference(serviceBusFailedNotificationsQueue, '2019-09-01').secretUriWithVersion})'
163165
gmmServiceBus__fullyQualifiedNamespace: '@Microsoft.KeyVault(SecretUri=${reference(serviceBusFQN, '2019-09-01').secretUriWithVersion})'
164166
'graphCredentials:UserAssignedManagedIdentityClientId': '@Microsoft.KeyVault(SecretUri=${reference(graphUserAssignedManagedIdentityClientId, '2019-09-01').secretUriWithVersion})'
165167
}

Service/GroupMembershipManagement/Hosts/Notifier/Services.Notifier.Contracts/INotifierService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Models.ThresholdNotifications;
55
using System;
66
using System.Collections.Generic;
7+
using System.Net.Http;
78
using System.Text.Json;
89
using System.Threading.Tasks;
910

0 commit comments

Comments
 (0)