Browse Source

Final adjustments to make envoy work with ingress and remove Polly from http calls

features/migration-dotnet3
eiximenis 5 years ago
parent
commit
08e9b2641a
20 changed files with 187 additions and 232 deletions
  1. +22
    -6
      k8s/gen-k8s-env-aks.ps1
  2. +0
    -33
      k8s/gen-k8s-env.ps1
  3. +25
    -3
      k8s/helm/apigwmm/envoy.yaml
  4. +43
    -11
      k8s/helm/apigwms/envoy.yaml
  5. +27
    -5
      k8s/helm/apigwwm/envoy.yaml
  6. +1
    -1
      k8s/helm/apigwwm/templates/ingress.yaml
  7. +44
    -12
      k8s/helm/apigwws/envoy.yaml
  8. +4
    -0
      k8s/helm/webspa/templates/deployment.yaml
  9. +0
    -1
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj
  10. +2
    -13
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/GrpcCallerService.cs
  11. +0
    -25
      src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs
  12. +3
    -13
      src/ApiGateways/Web.Bff.Shopping/aggregator/Services/GrpcCallerService.cs
  13. +0
    -26
      src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs
  14. +1
    -34
      src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj
  15. +8
    -11
      src/Web/WebMVC/Controllers/CartController.cs
  16. +3
    -3
      src/Web/WebMVC/Controllers/OrderController.cs
  17. +1
    -27
      src/Web/WebMVC/Startup.cs
  18. +1
    -3
      src/Web/WebMVC/ViewComponents/Cart.cs
  19. +2
    -4
      src/Web/WebMVC/ViewComponents/CartList.cs
  20. +0
    -1
      src/Web/WebMVC/WebMVC.csproj

+ 22
- 6
k8s/gen-k8s-env-aks.ps1 View File

@ -4,9 +4,12 @@
[parameter(Mandatory=$true)][string]$serviceName,
[parameter(Mandatory=$true)][string]$dnsNamePrefix,
[parameter(Mandatory=$false)][string]$registryName,
[parameter(Mandatory=$true)][string]$createAcr=$true,
[parameter(Mandatory=$true)][bool]$createAcr=$true,
[parameter(Mandatory=$false)][int]$nodeCount=3,
[parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2"
[parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2",
[parameter(Mandatory=$false)][bool]$enableHttpApplicationAddon=$true,
[parameter(Mandatory=$false)][bool]$enableAzureMonitoring=$false,
[parameter(Mandatory=$false)][ValidateSet("VirtualMachineScaleSets","AvailabilitySet",IgnoreCase=$true)]$vmSetType="VirtualMachineScaleSets"
)
# Create resource group
@ -15,13 +18,26 @@ az group create --name=$resourceGroupName --location=$location
if ($createAcr -eq $true) {
# Create Azure Container Registry
Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow
if ([string]::IsNullOrEmpty($registryName)) {
$registryName=$serviceName
}
Write-Host "Creating Azure Container Registry named $registryName" -ForegroundColor Yellow
az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic
}
# Create kubernetes cluster in AKS
Write-Host "Creating Kubernetes cluster in AKS..." -ForegroundColor Yellow
az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize
Write-Host "Creating AKS $resourceGroupName/$serviceName" -ForegroundColor Yellow
az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize --vm-set-type $vmSetType
if ($enableHttpApplicationAddon) {
Write-Host "Enabling Http Applciation Routing in AKS $serviceName" -ForegroundColor Yellow
az aks enable-addons --resource-group $resourceGroupName --name $serviceName --addons http_application_routing
}
if ($enableAzureMonitoring) {
Write-Host "Enabling Azure Monitoring in AKS $serviceName" -ForegroundColor Yellow
az aks enable-addons --resource-group $resourceGroupName --name $serviceName --addons monitoring
}
# Retrieve kubernetes cluster configuration and save it under ~/.kube/config
Write-Host "Getting Kubernetes config..." -ForegroundColor Yellow
@ -29,6 +45,6 @@ az aks get-credentials --resource-group=$resourceGroupName --name=$serviceName
if ($createAcr -eq $true) {
# Show ACR credentials
Write-Host "ACR credentials" -ForegroundColor Yellow
Write-Host "ACR $registryName credentials:" -ForegroundColor Yellow
az acr credential show -n $registryName
}

+ 0
- 33
k8s/gen-k8s-env.ps1 View File

@ -1,33 +0,0 @@
Param(
[parameter(Mandatory=$true)][string]$resourceGroupName,
[parameter(Mandatory=$true)][string]$location,
[parameter(Mandatory=$false)][string]$registryName,
[parameter(Mandatory=$true)][string]$orchestratorName,
[parameter(Mandatory=$true)][string]$dnsName,
[parameter(Mandatory=$true)][string]$createAcr=$true,
[parameter(Mandatory=$false)][int]$agentCount=2,
[parameter(Mandatory=$false)][string]$agentVMSize="Standard_D2_v2",
[parameter(Mandatory=$false)][int]$masterCount=1
)
# Create resource group
Write-Host "Creating resource group..." -ForegroundColor Yellow
az group create --name=$resourceGroupName --location=$location
if ($createAcr -eq $true) {
# Create Azure Container Registry
Write-Host "Creating Azure Container Registry..." -ForegroundColor Yellow
az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic
}
# Create kubernetes orchestrator
Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow
az acs create --orchestrator-type=kubernetes --resource-group $resourceGroupName --name=$orchestratorName --dns-prefix=$dnsName --generate-ssh-keys --agent-count=$agentCount --agent-vm-size=$agentVMSize --master-count=$masterCount
# Retrieve kubernetes cluster configuration and save it under ~/.kube/config
az acs kubernetes get-credentials --resource-group=$resourceGroupName --name=$orchestratorName
if ($createAcr -eq $true) {
# Show ACR credentials
az acr credential show -n $registryName
}

+ 25
- 3
k8s/helm/apigwmm/envoy.yaml View File

@ -23,17 +23,39 @@ static_resources:
domains:
- "*"
routes:
- match:
- name: "m-short"
match:
prefix: "/m/"
route:
auto_host_rewrite: true
prefix_rewrite: "/marketing-api/"
cluster: marketing
- match:
- name: "m-long"
match:
prefix: "/marketing-api/"
route:
auto_host_rewrite: true
cluster: marketing
http_filters:
- name: envoy.router
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: marketing
connect_timeout: 0.25s


+ 43
- 11
k8s/helm/apigwms/envoy.yaml View File

@ -23,44 +23,76 @@ static_resources:
domains:
- "*"
routes:
- match:
- name: "c-short"
match:
prefix: "/c/"
route:
auto_host_rewrite: true
prefix_rewrite: "/catalog-api/"
cluster: catalog
- match:
- name: "c-long"
match:
prefix: "/catalog-api/"
route:
auto_host_rewrite: true
cluster: catalog
- match:
- name: "o-short"
match:
prefix: "/o/"
route:
auto_host_rewrite: true
prefix_rewrite: "/ordering-api/"
cluster: ordering
- match:
- name: "o-long"
match:
prefix: "/ordering-api/"
route:
auto_host_rewrite: true
cluster: ordering
- match:
- name: "b-short"
match:
prefix: "/b/"
route:
auto_host_rewrite: true
prefix_rewrite: "/basket-api/"
cluster: basket
- match:
- name: "b-long"
match:
prefix: "/basket-api/"
route:
auto_host_rewrite: true
cluster: basket
- match:
- name: "agg"
match:
prefix: "/"
route:
auto_host_rewrite: true
prefix_rewrite: "/"
cluster: shoppingagg
http_filters:
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: shoppingagg
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -68,7 +100,7 @@ static_resources:
port_value: 80
- name: catalog
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -76,7 +108,7 @@ static_resources:
port_value: 80
- name: basket
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -84,7 +116,7 @@ static_resources:
port_value: 80
- name: ordering
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:


+ 27
- 5
k8s/helm/apigwwm/envoy.yaml View File

@ -23,21 +23,43 @@ static_resources:
domains:
- "*"
routes:
- match:
- name: "m-short"
match:
prefix: "/m/"
route:
auto_host_rewrite: true
prefix_rewrite: "/marketing-api/"
cluster: marketing
- match:
- name: "m-long"
match:
prefix: "/marketing-api/"
route:
auto_host_rewrite: true
cluster: marketing
http_filters:
- name: envoy.router
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: marketing
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -45,7 +67,7 @@ static_resources:
port_value: 80
- name: locations
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:


+ 1
- 1
k8s/helm/apigwwm/templates/ingress.yaml View File

@ -1,4 +1,4 @@
ç{{- if .Values.ingress.enabled -}}
{{- if .Values.ingress.enabled -}}
{{- $ingressPath := include "pathBase" . -}}
{{- $serviceName := .Values.app.svc.webmarketingapigw -}}


+ 44
- 12
k8s/helm/apigwws/envoy.yaml View File

@ -23,44 +23,76 @@ static_resources:
domains:
- "*"
routes:
- match:
- name: "c-short"
match:
prefix: "/c/"
route:
auto_host_rewrite: true
prefix_rewrite: "/catalog-api/"
cluster: catalog
- match:
- name: "c-long"
match:
prefix: "/catalog-api/"
route:
auto_host_rewrite: true
cluster: catalog
- match:
- name: "o-short"
match:
prefix: "/o/"
route:
auto_host_rewrite: true
prefix_rewrite: "/ordering-api/"
cluster: ordering
- match:
- name: "o-long"
match:
prefix: "/ordering-api/"
route:
auto_host_rewrite: true
cluster: ordering
- match:
- name: "b-short"
match:
prefix: "/b/"
route:
auto_host_rewrite: true
prefix_rewrite: "/basket-api/"
cluster: basket
- match:
- name: "b-long"
match:
prefix: "/basket-api/"
route:
auto_host_rewrite: true
cluster: basket
- match:
- name: "agg"
match:
prefix: "/"
route:
auto_host_rewrite: true
prefix_rewrite: "/"
cluster: shoppingagg
http_filters:
- name: envoy.router
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: shoppingagg
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -68,7 +100,7 @@ static_resources:
port_value: 80
- name: catalog
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -76,7 +108,7 @@ static_resources:
port_value: 80
- name: basket
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
@ -84,7 +116,7 @@ static_resources:
port_value: 80
- name: ordering
connect_timeout: 0.25s
type: logical_dns
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:


+ 4
- 0
k8s/helm/webspa/templates/deployment.yaml View File

@ -21,6 +21,10 @@ spec:
labels:
app: {{ template "webspa.name" . }}
release: {{ .Release.Name }}
{{ if .Values.inf.mesh.enabled -}}
annotations:
linkerd.io/inject: enabled
{{- end }}
spec:
{{ if .Values.inf.registry -}}
imagePullSecrets:


+ 0
- 1
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj View File

@ -26,7 +26,6 @@
<PackageReference Include="Serilog.AspNetCore" Version="3.0.1-dev-00099" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.2-dev-00824" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.0.0-rc1.19456.10" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0-rc1.19457.4" />
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.6.0-rc1.19456.4" />
</ItemGroup>


+ 2
- 13
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/GrpcCallerService.cs View File

@ -3,7 +3,6 @@ using System.Threading.Tasks;
using System;
using Grpc.Core;
using Serilog;
using Polly;
using Grpc.Net.Client;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
@ -30,11 +29,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
try
{
return await Policy
.Handle<Exception>(ex => true)
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (e, t) => Log.Warning("Retrying the call to urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress}, errorMessage={@message}", urlGrpc, channel.Target, e.Message))
.ExecuteAsync(() => func(channel))
;
return await func(channel);
}
catch (RpcException e)
{
@ -46,8 +41,6 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", false);
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", false);
}
}
public static async Task CallService(string urlGrpc, Func<GrpcChannel, Task> func)
@ -68,11 +61,7 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
try
{
await Policy
.Handle<Exception>(ex => true)
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (e, t) => Log.Warning("Retrying the call to urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress}, errorMessage={@message}", urlGrpc, channel.Target, e.Message))
.ExecuteAsync(() => func(channel))
;
await func(channel);
}
catch (RpcException e)
{


+ 0
- 25
src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs View File

@ -14,12 +14,9 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Polly;
using Polly.Extensions.Http;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
{
@ -184,41 +181,19 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator
services
.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<IOrderingService, OrderingService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
return services;
}
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
}

+ 3
- 13
src/ApiGateways/Web.Bff.Shopping/aggregator/Services/GrpcCallerService.cs View File

@ -1,9 +1,7 @@
using System.Net.Http;
using System.Threading.Tasks;
using System.Threading.Tasks;
using System;
using Grpc.Core;
using Serilog;
using Polly;
using Grpc.Net.Client;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
@ -30,11 +28,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
try
{
return await Policy
.Handle<Exception>(ex => true)
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (e, t) => Log.Warning("Retrying the call to urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress}, errorMessage={@message}", urlGrpc, channel.Target, e.Message))
.ExecuteAsync(() => func(channel))
;
return await func(channel);
}
catch (RpcException e)
{
@ -68,11 +62,7 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
try
{
await Policy
.Handle<Exception>(ex => true)
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (e, t) => Log.Warning("Retrying the call to urlGrpc ={@urlGrpc}, BaseAddress={@BaseAddress}, errorMessage={@message}", urlGrpc, channel.Target, e.Message))
.ExecuteAsync(() => func(channel))
;
await func(channel);
}
catch (RpcException e)
{


+ 0
- 26
src/ApiGateways/Web.Bff.Shopping/aggregator/Startup.cs View File

@ -15,13 +15,9 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Polly;
using Polly.Extensions.Http;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
{
@ -188,44 +184,22 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator
services.AddHttpClient<IBasketService, BasketService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<IOrderingService, OrderingService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
}

+ 1
- 34
src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj View File

@ -1,36 +1,4 @@
<!--<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>$(NetCoreTargetVersion)</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
<LangVersion>$(LangVersion)</LangVersion>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="$(AspNetCore_HealthChecks_Uris)" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="$(AspNetCore_HealthChecks_UI_Client)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="$(Microsoft_AspNetCore_Diagnostics_HealthChecks)" />
<PackageReference Include="Serilog.AspNetCore" Version="$(Serilog_AspNetCore)" />
<PackageReference Include="Serilog.Sinks.Console" Version="$(Serilog_Sinks_Console)" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="$(Microsoft_Extensions_Http_Polly)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(Microsoft_AspNetCore_Authentication_JwtBearer)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
</ItemGroup>
</Project>-->
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>$(NetCoreTargetVersion)</TargetFramework>
@ -59,7 +27,6 @@
<PackageReference Include="Serilog.AspNetCore" Version="3.0.1-dev-00099" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.2-dev-00824" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="$(Swashbuckle_AspNetCore)" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.0.0-rc1.19456.10" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0-rc1.19457.4" />
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.6.0-rc1.19456.4" />
</ItemGroup>


+ 8
- 11
src/Web/WebMVC/Controllers/CartController.cs View File

@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Polly.CircuitBreaker;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -32,10 +31,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return View(vm);
}
catch (BrokenCircuitException)
catch (Exception ex)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
HandleException(ex);
}
return View();
@ -54,10 +52,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return RedirectToAction("Create", "Order");
}
}
catch (BrokenCircuitException)
catch (Exception ex)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
HandleException(ex);
}
return View();
@ -74,18 +71,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
}
return RedirectToAction("Index", "Catalog");
}
catch (BrokenCircuitException)
catch (Exception ex)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
HandleException(ex);
}
return RedirectToAction("Index", "Catalog", new { errorMsg = ViewBag.BasketInoperativeMsg });
}
private void HandleBrokenCircuitException()
private void HandleException(Exception ex)
{
ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
ViewBag.BasketInoperativeMsg = $"Basket Service is inoperative {ex.GetType().Name} - {ex.Message}";
}
}
}

+ 3
- 3
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Polly.CircuitBreaker;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
@ -47,9 +47,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return RedirectToAction("Index");
}
}
catch (BrokenCircuitException)
catch (Exception ex)
{
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
ModelState.AddModelError("Error", $"It was not possible to create a new order, please try later on ({ex.GetType().Name} - {ex.Message})");
}
return View("Create", model);


+ 1
- 27
src/Web/WebMVC/Startup.cs View File

@ -15,8 +15,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Logging;
using Polly;
using Polly.Extensions.Http;
using StackExchange.Redis;
using System;
using System.IdentityModel.Tokens.Jwt;
@ -146,7 +144,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
return services;
}
// Adds all Http client services (like Service-Agents) using resilient Http requests based on HttpClient factory and Polly's policies
// Adds all Http client services
public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
@ -162,32 +160,22 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddHttpClient<IBasketService, BasketService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Sample. Default lifetime is 2 minutes
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<ICatalogService, CatalogService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<IOrderingService, OrderingService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddHttpMessageHandler<HttpClientRequestIdDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<ICampaignService, CampaignService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
services.AddHttpClient<ILocationService, LocationService>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy())
.AddDevspacesSupport();
//add custom application services
@ -235,19 +223,5 @@ namespace Microsoft.eShopOnContainers.WebMVC
return services;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}
}
}

+ 1
- 3
src/Web/WebMVC/ViewComponents/Cart.cs View File

@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{
@ -25,9 +24,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
vm.ItemsCount = itemsInCart;
return View(vm);
}
catch (BrokenCircuitException)
catch
{
// Catch error when Basket.api is in circuit-opened mode
ViewBag.IsBasketInoperative = true;
}


+ 2
- 4
src/Web/WebMVC/ViewComponents/CartList.cs View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{
@ -23,10 +22,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
vm = await GetItemsAsync(user);
return View(vm);
}
catch (BrokenCircuitException)
catch (Exception ex)
{
// Catch error when Basket.api is in circuit-opened mode
ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
ViewBag.BasketInoperativeMsg = $"Basket Service is inoperative, please try later on. ({ex.GetType().Name} - {ex.Message}))";
}
return View(vm);


+ 0
- 1
src/Web/WebMVC/WebMVC.csproj View File

@ -31,7 +31,6 @@
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="$(Microsoft_AspNetCore_Diagnostics_HealthChecks)" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="$(Microsoft_AspNetCore_HealthChecks)" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.0.0-rc1.19456.10" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="3.0.0-rc1.19456.10" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="2.2.0-preview3-35458" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.0.461" />


Loading…
Cancel
Save