-
Notifications
You must be signed in to change notification settings - Fork 52
Карпов Владимир Лаб. 2 Группа 6512 #106
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
base: main
Are you sure you want to change the base?
Changes from all commits
be2d775
3f06194
5d6b4e7
81baeb1
9212048
d977691
0a154dc
1fc1a11
ff1d112
925e451
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 |
|---|---|---|
| @@ -1,10 +1,10 @@ | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning" | ||
| } | ||
| }, | ||
| "AllowedHosts": "*", | ||
| "BaseAddress": "" | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning" | ||
| } | ||
| }, | ||
| "AllowedHosts": "*", | ||
| "BaseAddress": "http://localhost:5300/warehouse-item" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| var cache = builder.AddRedis("warehouse-item-cache") | ||
| .WithRedisInsight(containerName: "warehouse-item-insight"); | ||
|
|
||
| var gateway = builder.AddProject<Projects.WarehouseItem_Gateway>("gateway") | ||
| .WithHttpEndpoint(name: "http", port: 5300) | ||
| .WithExternalHttpEndpoints(); | ||
|
|
||
| const int generatorPortBase = 5200; | ||
| for (var i = 1; i <= 5; ++i) | ||
| { | ||
| var generator = builder.AddProject<Projects.WarehouseItem_Generator>($"generator-{i}") | ||
| .WithReference(cache, "warehouse-item-cache") | ||
| .WithHttpEndpoint(name: "http", port: generatorPortBase + i) | ||
| .WaitFor(cache); | ||
|
|
||
| gateway.WaitFor(generator); | ||
| } | ||
|
|
||
| builder.AddProject<Projects.Client_Wasm>("client") | ||
| .WithReference(gateway) | ||
| .WaitFor(gateway); | ||
|
|
||
| builder.Build().Run(); | ||
|
|
||
|
|
||
|
|
||
|
Comment on lines
+26
to
+28
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. Лишние строки |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| { | ||
| "$schema": "https://json.schemastore.org/launchsettings.json", | ||
| "profiles": { | ||
| "https": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "https://localhost:17129;http://localhost:15221", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21101", | ||
| "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22255" | ||
| } | ||
| }, | ||
| "http": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "http://localhost:15221", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19083", | ||
| "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20274" | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <Sdk Name="Aspire.AppHost.Sdk" Version="9.5.2" /> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <UserSecretsId>ed7e1e47-dc98-4419-8424-85412466aa9b</UserSecretsId> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.2" /> | ||
| <PackageReference Include="Aspire.Hosting.Redis" Version="9.5.2" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="..\WarehouseItem.Generator\WarehouseItem.Generator.csproj" /> | ||
| <ProjectReference Include="..\Client.Wasm\Client.Wasm.csproj" /> | ||
| <ProjectReference Include="..\WarehouseItem.Gateway\WarehouseItem.Gateway.csproj" /> | ||
| </ItemGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning", | ||
| "Aspire.Hosting.Dcp": "Warning" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| using Ocelot.LoadBalancer.Interfaces; | ||
| using Ocelot.Responses; | ||
| using Ocelot.Values; | ||
|
|
||
| namespace WarehouseItem.Gateway.LoadBalancer; | ||
|
|
||
| /// <summary> | ||
| /// Query-based балансировщик нагрузки: выбирает downstream по query-параметру <c>id</c>. | ||
| /// Если параметр отсутствует/невалиден — выбирает случайный downstream. | ||
| /// </summary> | ||
| public sealed class QueryBasedLoadBalancer( | ||
| ILogger<QueryBasedLoadBalancer> logger, | ||
| Func<Task<List<Service>>> servicesProvider) : ILoadBalancer | ||
| { | ||
| private const string IdParam = "id"; | ||
|
|
||
| public string Type => nameof(QueryBasedLoadBalancer); | ||
|
|
||
| public void Release(ServiceHostAndPort hostAndPort) { } | ||
|
|
||
| public async Task<Response<ServiceHostAndPort>> LeaseAsync(HttpContext httpContext) | ||
| { | ||
| var services = await servicesProvider(); | ||
|
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. Возможно стоит добавить проверку, что |
||
|
|
||
| var selectedIndex = ChooseIndex(httpContext, services.Count, out var parsedId); | ||
|
|
||
| if (parsedId is null) | ||
| { | ||
| logger.LogWarning("Query param {param} missing/invalid; index={index} selected by random.", IdParam, | ||
| selectedIndex); | ||
| } | ||
| else | ||
| { | ||
| logger.LogInformation("Query-based selection: id={id} -> index={index}.", parsedId, selectedIndex); | ||
| } | ||
|
|
||
| return new OkResponse<ServiceHostAndPort>(services[selectedIndex].HostAndPort); | ||
| } | ||
|
|
||
| private static int ChooseIndex(HttpContext httpContext, int servicesCount, out int? id) | ||
| { | ||
| id = null; | ||
|
|
||
| if (TryParseId(httpContext, out var parsed)) | ||
| { | ||
| id = parsed; | ||
| return parsed % servicesCount; | ||
| } | ||
|
|
||
| return Random.Shared.Next(servicesCount); | ||
| } | ||
|
|
||
| private static bool TryParseId(HttpContext httpContext, out int id) | ||
| { | ||
| id = 0; | ||
|
|
||
| if (!httpContext.Request.Query.TryGetValue(IdParam, out var values) || values.Count == 0) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var raw = values[0]; | ||
| return !string.IsNullOrWhiteSpace(raw) && int.TryParse(raw, out id) && id >= 0; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using Ocelot.DependencyInjection; | ||
| using Ocelot.Middleware; | ||
| using WarehouseItem.Gateway.LoadBalancer; | ||
| using WarehouseItem.ServiceDefaults; | ||
|
|
||
| var builder = WebApplication.CreateBuilder(args); | ||
|
|
||
| const string CorsPolicyName = "LocalDev"; | ||
|
|
||
| builder.AddServiceDefaults(); | ||
|
|
||
| builder.Services.AddCors(static options => | ||
| { | ||
| options.AddPolicy(CorsPolicyName, static policy => | ||
| policy.AllowAnyOrigin() | ||
|
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. Можно еще добавить разрешенные origins |
||
| .WithHeaders("Content-Type") | ||
| .WithMethods("GET")); | ||
| }); | ||
|
|
||
| builder.Configuration | ||
| .AddJsonFile("ocelot.json", optional: false, reloadOnChange: true) | ||
| .AddOcelot(); | ||
|
|
||
| builder.Services | ||
| .AddOcelot(builder.Configuration) | ||
| .AddCustomLoadBalancer((sp, _, discoveryProvider) => | ||
| new QueryBasedLoadBalancer( | ||
| sp.GetRequiredService<ILogger<QueryBasedLoadBalancer>>(), | ||
| discoveryProvider.GetAsync)); | ||
|
|
||
| var app = builder.Build(); | ||
|
|
||
| app.UseCors(CorsPolicyName); | ||
|
|
||
| await app.UseOcelot(); | ||
| await app.RunAsync(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Ocelot" Version="24.1.0" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\WarehouseItem.ServiceDefaults\WarehouseItem.ServiceDefaults.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "Routes": [ | ||
| { | ||
| "DownstreamPathTemplate": "/api/warehouse-item", | ||
| "DownstreamScheme": "http", | ||
| "DownstreamHostAndPorts": [ | ||
| { "Host": "localhost", "Port": 5201 }, | ||
| { "Host": "localhost", "Port": 5202 }, | ||
| { "Host": "localhost", "Port": 5203 }, | ||
| { "Host": "localhost", "Port": 5204 }, | ||
| { "Host": "localhost", "Port": 5205 } | ||
| ], | ||
| "UpstreamPathTemplate": "/warehouse-item", | ||
| "UpstreamHttpMethod": [ "GET" ], | ||
| "LoadBalancerOptions": { | ||
| "Type": "QueryBasedLoadBalancer" | ||
| } | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using Microsoft.AspNetCore.Mvc; | ||
| using WarehouseItem.Generator.DTO; | ||
| using WarehouseItem.Generator.Service; | ||
|
|
||
| namespace WarehouseItem.Generator.Controller; | ||
|
|
||
| /// <summary> | ||
| /// API контроллер для работы с товарами склада. | ||
| /// </summary> | ||
| [ApiController] | ||
| [Route("api/warehouse-item")] | ||
| public sealed class WarehouseItemController(ILogger<WarehouseItemController> logger, IWarehouseItemService service) : ControllerBase | ||
| { | ||
| /// <summary> | ||
| /// Получить товар по id. | ||
| /// </summary> | ||
| /// <param name="id">Идентификатор товара</param> | ||
| /// <param name="cancellationToken">Токен отмены</param> | ||
| /// <returns>Данные товара</returns> | ||
| [HttpGet] | ||
| [ProducesResponseType(typeof(WarehouseItemDto), StatusCodes.Status200OK)] | ||
| [ProducesResponseType(StatusCodes.Status400BadRequest)] | ||
| public async Task<ActionResult<WarehouseItemDto>> Get([FromQuery] int id, CancellationToken cancellationToken) | ||
| { | ||
| if (id < 0) | ||
| { | ||
| return BadRequest(new { message = "id cannot be negative" }); | ||
| } | ||
|
|
||
| logger.LogInformation("Request warehouse item id={id}.", id); | ||
| var dto = await service.GetAsync(id, cancellationToken); | ||
| logger.LogInformation("Response warehouse item id={id}.", id); | ||
|
|
||
| return Ok(dto); | ||
| } | ||
| } |
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.
Раньше отступы лучше выглядели