Browse Source

feat: 增加对聚合错误处理

pull/467/head
cKey 4 years ago
parent
commit
6b0c5ec827
  1. 2
      aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Program.cs
  2. 2
      aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/Program.cs
  3. 2
      aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/Program.cs
  4. 2
      aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/Program.cs
  5. 8
      aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs
  6. 2
      aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/Program.cs
  7. 2
      aspnet-core/services/LY.MicroService.identityServer/Program.cs
  8. 5
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayOptions.cs
  9. 68
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Ocelot/Multiplexer/AbpResponseMergeAggregator.cs
  10. 77
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Program.cs
  11. 2
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Properties/launchSettings.json
  12. 31
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Startup.cs
  13. 56
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json
  14. 6
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.aggregate.json
  15. 87
      gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.task.json

2
aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

2
aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

2
aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

2
aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

8
aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/Program.cs

@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Serilog; using Serilog;
using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.IO; using Volo.Abp.IO;
@ -50,6 +51,13 @@ public class Program
await app.RunAsync(); await app.RunAsync();
return 0; return 0;
} }
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1;
}
finally finally
{ {
Log.CloseAndFlush(); Log.CloseAndFlush();

2
aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

2
aspnet-core/services/LY.MicroService.identityServer/Program.cs

@ -54,6 +54,8 @@ public class Program
catch (Exception ex) catch (Exception ex)
{ {
Log.Fatal(ex, "Host terminated unexpectedly!"); Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1; return 1;
} }
finally finally

5
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayOptions.cs

@ -4,9 +4,14 @@ namespace LINGYUN.MicroService.Internal.ApiGateway
{ {
public class InternalApiGatewayOptions public class InternalApiGatewayOptions
{ {
/// <summary>
/// 聚合异常时是否忽略
/// </summary>
public bool AggregationIgnoreError { get; set; }
public DownstreamOpenApi[] DownstreamOpenApis { get; set; } public DownstreamOpenApi[] DownstreamOpenApis { get; set; }
public InternalApiGatewayOptions() public InternalApiGatewayOptions()
{ {
AggregationIgnoreError = true;
DownstreamOpenApis = new DownstreamOpenApi[0]; DownstreamOpenApis = new DownstreamOpenApi[0];
} }
} }

68
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Ocelot/Multiplexer/AbpResponseMergeAggregator.cs

@ -1,4 +1,8 @@
using Microsoft.AspNetCore.Http; using LINGYUN.MicroService.Internal.ApiGateway;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Ocelot.Middleware; using Ocelot.Middleware;
@ -14,6 +18,17 @@ namespace Ocelot.Multiplexer
{ {
public class AbpResponseMergeAggregator : IDefinedAggregator public class AbpResponseMergeAggregator : IDefinedAggregator
{ {
public ILogger<AbpResponseMergeAggregator> Logger { protected get; set; }
protected InternalApiGatewayOptions Options { get; }
public AbpResponseMergeAggregator(
IOptions<InternalApiGatewayOptions> options)
{
Options = options.Value;
Logger = NullLogger<AbpResponseMergeAggregator>.Instance;
}
public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses) public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
{ {
return await MapAbpApiDefinitionAggregateContentAsync(responses); return await MapAbpApiDefinitionAggregateContentAsync(responses);
@ -29,7 +44,41 @@ namespace Ocelot.Multiplexer
}; };
foreach (var httpResponse in responses) foreach (var httpResponse in responses)
{ {
var content = await httpResponse.Items.DownstreamResponse().Content.ReadAsStringAsync(); var errorItems = httpResponse.Items.Errors();
var response = httpResponse.Items.DownstreamResponse();
if (errorItems.Any())
{
if (!Options.AggregationIgnoreError)
{
var errorItem = errorItems.First();
string error = errorItems.Select(x => x.Message).JoinAsString(";");
if (httpResponse.Response.Headers.ContainsKey(AbpHttpConsts.AbpErrorFormat))
{
// header 存在abp错误标头, 可以序列化错误信息
error = await response.Content.ReadAsStringAsync();
}
var errorContent = new StringContent(error)
{
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
};
if (httpResponse.Response.Headers.ContainsKey(AbpHttpConsts.AbpErrorFormat))
{
errorContent.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
}
return new DownstreamResponse(
errorContent,
(HttpStatusCode)errorItem.HttpStatusCode,
httpResponse.Response.Headers.Select(x => new Header(x.Key, x.Value)).ToList(),
errorItem.Message);
}
var route = httpResponse.Items.DownstreamRoute();
var service = route.ServiceName ?? route.LoadBalancerKey ?? route.DownstreamPathTemplate.Value;
Logger.LogWarning($"The downstream service {service} returned an error, which is configured to be ignored");
continue;
}
var content = await response.Content.ReadAsStringAsync();
var contentObject = JsonConvert.DeserializeObject(content); var contentObject = JsonConvert.DeserializeObject(content);
if (responseObject == null) if (responseObject == null)
{ {
@ -45,13 +94,16 @@ namespace Ocelot.Multiplexer
Headers = { ContentType = new MediaTypeHeaderValue("application/json") } Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
}; };
if (responses.Any(response => response.Response.Headers.ContainsKey(AbpHttpConsts.AbpErrorFormat))) //if (responses.Any(response => response.Response.Headers.ContainsKey(AbpHttpConsts.AbpErrorFormat)))
{ //{
stringContent.Headers.Add("_AbpErrorFormat", "true"); // stringContent.Headers.Add("_AbpErrorFormat", "true");
} //}
return new DownstreamResponse(stringContent, HttpStatusCode.OK, return new DownstreamResponse(
new List<KeyValuePair<string, IEnumerable<string>>>(), "OK"); stringContent,
HttpStatusCode.OK,
new List<KeyValuePair<string, IEnumerable<string>>>(),
"OK");
} }
} }

77
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Program.cs

@ -1,46 +1,35 @@
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Serilog; using Serilog;
using System; using System;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.IO;
using Volo.Abp.Modularity.PlugIns;
namespace LINGYUN.MicroService.Internal.ApiGateway namespace LINGYUN.MicroService.Internal.ApiGateway;
public class Program
{ {
public class Program public async static Task<int> Main(string[] args)
{
public static int Main(string[] args)
{ {
try try
{ {
var hostBuilder = CreateHostBuilder(args).Build(); Log.Information("Starting Internal ApiGateway.");
Log.Information("Starting ApiGateway.Host.");
hostBuilder.Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
internal static IHostBuilder CreateHostBuilder(string[] args) => var builder = WebApplication.CreateBuilder(args);
Host.CreateDefaultBuilder(args) builder.Host.AddAppSettingsSecretsJson()
.ConfigureWebHostDefaults(webBuilder => .UseAutofac()
{
webBuilder.UseStartup<Startup>();
})
.ConfigureAppConfiguration((context, config) => .ConfigureAppConfiguration((context, config) =>
{ {
// 加入 ocelot配置文件 // 加入 ocelot配置文件
config config.AddJsonFile(
.AddJsonFile($"ocelot.{context.HostingEnvironment.EnvironmentName ?? "Development"}.json", optional: true, reloadOnChange: true); $"ocelot.{context.HostingEnvironment.EnvironmentName ?? "Development"}.json",
optional: true,
reloadOnChange: true);
var configuration = config.Build(); var configuration = config.Build();
if (configuration.GetSection("AgileConfig").Exists()) if (configuration.GetSection("AgileConfig").Exists())
@ -51,7 +40,33 @@ namespace LINGYUN.MicroService.Internal.ApiGateway
.UseSerilog((context, provider, config) => .UseSerilog((context, provider, config) =>
{ {
config.ReadFrom.Configuration(context.Configuration); config.ReadFrom.Configuration(context.Configuration);
}) });
.UseAutofac(); await builder.AddApplicationAsync<InternalApiGatewayModule>(options =>
{
// 搜索 Modules 目录下所有文件作为插件
// 取消显示引用所有其他项目的模块,改为通过插件的形式引用
var pluginFolder = Path.Combine(
Directory.GetCurrentDirectory(), "Modules");
DirectoryHelper.CreateIfNotExists(pluginFolder);
options.PlugInSources.AddFolder(
pluginFolder,
SearchOption.AllDirectories);
});
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
Console.WriteLine("Host terminated unexpectedly!");
Console.WriteLine(ex.ToString());
return 1;
}
finally
{
Log.CloseAndFlush();
}
} }
} }

2
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Properties/launchSettings.json

@ -12,7 +12,7 @@
"commandName": "Project", "commandName": "Project",
"launchBrowser": false, "launchBrowser": false,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Production"
}, },
"applicationUrl": "https://127.0.0.1:30443;http://127.0.0.1:30000" "applicationUrl": "https://127.0.0.1:30443;http://127.0.0.1:30000"
} }

31
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/Startup.cs

@ -1,31 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using Volo.Abp.IO;
using Volo.Abp.Modularity.PlugIns;
namespace LINGYUN.MicroService.Internal.ApiGateway
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<InternalApiGatewayModule>(options =>
{
// 搜索 Modules 目录下所有文件作为插件
// 取消显示引用所有其他项目的模块,改为通过插件的形式引用
var pluginFolder = Path.Combine(
Directory.GetCurrentDirectory(), "Modules");
DirectoryHelper.CreateIfNotExists(pluginFolder);
options.PlugInSources.AddFolder(
pluginFolder,
SearchOption.AllDirectories);
});
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}

56
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json

@ -1370,6 +1370,56 @@
"UseTracing": true "UseTracing": true
} }
}, },
{
"DownstreamPathTemplate": "/api/abp/application-configuration",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30040
}
],
"UpstreamPathTemplate": "/api/abp/task/application-configuration",
"UpstreamHttpMethod": [ "GET" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "task-configuration"
},
{
"DownstreamPathTemplate": "/api/abp/api-definition",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30040
}
],
"UpstreamPathTemplate": "/api/abp/task/api-definition",
"UpstreamHttpMethod": [ "GET" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "task-api-definition"
},
{ {
"DownstreamPathTemplate": "/api/task-management/{everything}", "DownstreamPathTemplate": "/api/task-management/{everything}",
"DownstreamScheme": "http", "DownstreamScheme": "http",
@ -1585,7 +1635,8 @@
"backend-admin-api-definition", "backend-admin-api-definition",
"messages-api-definition", "messages-api-definition",
"ids-admin-api-definition", "ids-admin-api-definition",
"localization-api-definition" "localization-api-definition",
"task-api-definition"
], ],
"UpstreamPathTemplate": "/api/abp/api-definition", "UpstreamPathTemplate": "/api/abp/api-definition",
"Aggregator": "AbpResponseMergeAggregator" "Aggregator": "AbpResponseMergeAggregator"
@ -1596,7 +1647,8 @@
"backend-admin-configuration", "backend-admin-configuration",
"messages-configuration", "messages-configuration",
"ids-admin-configuration", "ids-admin-configuration",
"localization-configuration" "localization-configuration",
"task-configuration"
], ],
"UpstreamPathTemplate": "/api/abp/application-configuration", "UpstreamPathTemplate": "/api/abp/application-configuration",
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",

6
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.aggregate.json

@ -7,7 +7,8 @@
"backend-admin-api-definition", "backend-admin-api-definition",
"messages-api-definition", "messages-api-definition",
"ids-admin-api-definition", "ids-admin-api-definition",
"localization-api-definition" "localization-api-definition",
"task-api-definition"
], ],
"UpstreamPathTemplate": "/api/abp/api-definition", "UpstreamPathTemplate": "/api/abp/api-definition",
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",
@ -20,7 +21,8 @@
"backend-admin-configuration", "backend-admin-configuration",
"messages-configuration", "messages-configuration",
"ids-admin-configuration", "ids-admin-configuration",
"localization-configuration" "localization-configuration",
"task-configuration"
], ],
"UpstreamPathTemplate": "/api/abp/application-configuration", "UpstreamPathTemplate": "/api/abp/application-configuration",
"Aggregator": "AbpResponseMergeAggregator", "Aggregator": "AbpResponseMergeAggregator",

87
gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.task.json

@ -0,0 +1,87 @@
{
"Routes": [
//
{
"DownstreamPathTemplate": "/api/abp/application-configuration",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30040
}
],
"UpstreamPathTemplate": "/api/abp/task/application-configuration",
"UpstreamHttpMethod": [ "GET" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "task-configuration"
},
// API
{
"DownstreamPathTemplate": "/api/abp/api-definition",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30040
}
],
"UpstreamPathTemplate": "/api/abp/task/api-definition",
"UpstreamHttpMethod": [ "GET" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
},
"Key": "task-api-definition"
},
//
{
"DownstreamPathTemplate": "/api/task-management/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 30040
}
],
"UpstreamPathTemplate": "/api/task-management/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 5
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 10,
"DurationOfBreak": 1000,
"TimeoutValue": 10000
},
"HttpHandlerOptions": {
"UseTracing": true
}
}
]
}
Loading…
Cancel
Save