Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
974822e
Создал структуру проекта и забабахал модель
PripyatskyPrometheus Feb 22, 2026
3a5a4ea
Delete SoftwareProject.ApiService directory
PripyatskyPrometheus Feb 22, 2026
b803d52
Delete SoftwareProject.Web directory
PripyatskyPrometheus Feb 22, 2026
5f6b884
Добавил генератор и контроллер.
PripyatskyPrometheus Feb 23, 2026
9761727
Устранение конфликтов
PripyatskyPrometheus Feb 23, 2026
4524147
Неболшая калибровка
PripyatskyPrometheus Feb 23, 2026
7467676
Добавил описание
PripyatskyPrometheus Feb 23, 2026
12dd63b
Добавил работу клиента, которую прошляпил до этого:)
PripyatskyPrometheus Feb 25, 2026
0922e68
Исправил замечания
PripyatskyPrometheus Feb 26, 2026
b6814d1
Побился над кодировкой
PripyatskyPrometheus Feb 26, 2026
f30d735
Исправил версии
PripyatskyPrometheus Feb 27, 2026
26a96a3
Ещё одна порция исправлений
PripyatskyPrometheus Feb 28, 2026
af34dbb
Сделал, как надо
PripyatskyPrometheus Feb 28, 2026
9b8bfaa
Добавил токе
PripyatskyPrometheus Mar 1, 2026
f48f222
Выполнил вторую лабу (надеюсь, что выполнил, потому что это был какой…
PripyatskyPrometheus Mar 3, 2026
a1ae1c2
Небольшие поправки
PripyatskyPrometheus Mar 3, 2026
276fd54
.
PripyatskyPrometheus Mar 3, 2026
93f7d6c
Упростил задачу и починил кодировку в консоли
PripyatskyPrometheus Mar 4, 2026
027fd1a
...
PripyatskyPrometheus Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Client.Wasm/Components/StudentCard.razor
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Card>
<Card>
<CardHeader>
<Heading Size="HeadingSize.Is5"><Icon Name="IconName.User" /> Лабораторная работа</Heading>
</CardHeader>
<CardBody>
<UnorderedList Unstyled>
<UnorderedListItem>Номер <Strong>№X "Название лабораторной"</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№Х "Название варианта"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Фамилией Именем 65ХХ</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://puginarug.com/">Ссылка на форк</Link></UnorderedListItem>
<UnorderedListItem>Номер <Strong>№2 "Балансировка"</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№35 "Программный проект"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Челаевым Петром 6512</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://github.com/PripyatskyPrometheus/cloud-development">Ссылка на форк</Link></UnorderedListItem>
</UnorderedList>
</CardBody>
</Card>
</Card>
2 changes: 1 addition & 1 deletion Client.Wasm/wwwroot/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
}
},
"AllowedHosts": "*",
"BaseAddress": ""
"BaseAddress": "https://localhost:7190/api/projects"
}
24 changes: 24 additions & 0 deletions CloudDevelopment.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ VisualStudioVersion = 17.14.36811.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.Wasm", "Client.Wasm\Client.Wasm.csproj", "{AE7EEA74-2FE0-136F-D797-854FD87E022A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProgramProject.AppHost", "ProgramProject.AppHost\ProgramProject.AppHost.csproj", "{7FA94C9A-CD2C-4D76-A42C-5C0EEDC6D68D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProgramProject.ServiceDefaults", "ProgramProject.ServiceDefaults\ProgramProject.ServiceDefaults.csproj", "{213F5ADB-6769-02BA-8BFA-17C924D27341}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProgramProject.GenerationService", "ProgramProject.GenerationService\ProgramProject.GenerationService.csproj", "{66DBD8A2-6672-889D-9A17-D156226DCB66}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProgramProject.Gateway", "ProgramProject.Gateway\ProgramProject.Gateway.csproj", "{0C26CAD8-F259-19D3-8E5B-FB32D481F591}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,6 +23,22 @@ Global
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.Build.0 = Release|Any CPU
{7FA94C9A-CD2C-4D76-A42C-5C0EEDC6D68D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FA94C9A-CD2C-4D76-A42C-5C0EEDC6D68D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FA94C9A-CD2C-4D76-A42C-5C0EEDC6D68D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FA94C9A-CD2C-4D76-A42C-5C0EEDC6D68D}.Release|Any CPU.Build.0 = Release|Any CPU
{213F5ADB-6769-02BA-8BFA-17C924D27341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{213F5ADB-6769-02BA-8BFA-17C924D27341}.Debug|Any CPU.Build.0 = Debug|Any CPU
{213F5ADB-6769-02BA-8BFA-17C924D27341}.Release|Any CPU.ActiveCfg = Release|Any CPU
{213F5ADB-6769-02BA-8BFA-17C924D27341}.Release|Any CPU.Build.0 = Release|Any CPU
{66DBD8A2-6672-889D-9A17-D156226DCB66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66DBD8A2-6672-889D-9A17-D156226DCB66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66DBD8A2-6672-889D-9A17-D156226DCB66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66DBD8A2-6672-889D-9A17-D156226DCB66}.Release|Any CPU.Build.0 = Release|Any CPU
{0C26CAD8-F259-19D3-8E5B-FB32D481F591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C26CAD8-F259-19D3-8E5B-FB32D481F591}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C26CAD8-F259-19D3-8E5B-FB32D481F591}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C26CAD8-F259-19D3-8E5B-FB32D481F591}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
23 changes: 23 additions & 0 deletions ProgramProject.AppHost/AppHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache").WithRedisCommander();

// Сервис генерации теперь делится на 3 реплики
var generationService = builder.AddProject<Projects.ProgramProject_GenerationService>("generation-service")
.WithExternalHttpEndpoints()
.WithReference(cache)
.WaitFor(cache)
.WithReplicas(3);

// Шлюз
var gateway = builder.AddProject<Projects.ProgramProject_Gateway>("gateway")
.WithExternalHttpEndpoints()
.WithReference(generationService);

// Клиент теперь связывается с генератором через шлюз
var client = builder.AddProject<Projects.Client_Wasm>("client-wasm")
.WithExternalHttpEndpoints()
.WithReference(gateway)
.WaitFor(gateway);

builder.Build().Run();
24 changes: 24 additions & 0 deletions ProgramProject.AppHost/ProgramProject.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<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>f95b6f17-c3f7-4ae5-a722-409a54dda80d</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Client.Wasm\Client.Wasm.csproj" />
<ProjectReference Include="..\ProgramProject.Gateway\ProgramProject.Gateway.csproj" />
<ProjectReference Include="..\ProgramProject.GenerationService\ProgramProject.GenerationService.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.2" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.5.2" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions ProgramProject.AppHost/Properties/launchSettings.json
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:17028;http://localhost:15016",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21209",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22094"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15016",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19079",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20183"
}
}
}
}
8 changes: 8 additions & 0 deletions ProgramProject.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions ProgramProject.AppHost/appsettings.json
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"
}
}
}
3 changes: 3 additions & 0 deletions ProgramProject.Gateway/.filenesting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"help":"https://go.microsoft.com/fwlink/?linkid=866610"
}
47 changes: 47 additions & 0 deletions ProgramProject.Gateway/LoadBalancers/QueryBasedLoadBalancer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Ocelot.LoadBalancer.Interfaces;
using Ocelot.Responses;
using Ocelot.Values;

namespace ProgramProject.Gateway.LoadBalancers;

/// <summary>
/// Балансировщик для алгоритма Query Based
/// </summary>
public class QueryBasedLoadBalancer : ILoadBalancer
{
private readonly List<Service> _services;
private readonly ILogger<QueryBasedLoadBalancer> _logger;
private readonly string _queryParameterName;

public QueryBasedLoadBalancer(List<Service> services, ILogger<QueryBasedLoadBalancer> logger, string queryParameterName = "id")
{
_services = services;
_logger = logger;
_queryParameterName = queryParameterName;
}

public string Type => nameof(QueryBasedLoadBalancer);

public async Task<Response<ServiceHostAndPort>> LeaseAsync(HttpContext httpContext)
{
var idValue = ExtractIdFromQuery(httpContext);
var replicaIndex = Math.Abs(idValue) % _services.Count;
var selectedService = _services[replicaIndex];

_logger.LogInformation("Запрос с id={Id} направлен на реплику {Index}", idValue, replicaIndex);

return new OkResponse<ServiceHostAndPort>(selectedService.HostAndPort);
}

private int ExtractIdFromQuery(HttpContext context)
{
if (context.Request.Query.TryGetValue(_queryParameterName, out var idString))
{
if (int.TryParse(idString, out var id))
return id;
}
return 0;
}

public void Release(ServiceHostAndPort hostAndPort) { }
}
32 changes: 32 additions & 0 deletions ProgramProject.Gateway/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Kubernetes;
using ProgramProject.Gateway.LoadBalancers;

var builder = WebApplication.CreateBuilder(args);

// Добавляем конфигурацию с Ocelot
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

// Регистрируем балансировщик
builder.Services.AddOcelot()
.AddKubernetes() // провайдер, с которым всё запускается
.AddCustomLoadBalancer((serviceProvider, route, serviceDiscoveryProvider) =>
{
var logger = serviceProvider.GetRequiredService<ILogger<QueryBasedLoadBalancer>>();
var services = serviceDiscoveryProvider.GetAsync().GetAwaiter().GetResult().ToList();

var queryParameterName = route.LoadBalancerOptions?.Key ?? "id";

return new QueryBasedLoadBalancer(services, logger, queryParameterName);
});

// Добавляем Service Discovery
builder.Services.AddServiceDiscovery();

var app = builder.Build();

// Обрабатываем все входящие запросы с помощью Ocelot
await app.UseOcelot();

app.Run();
20 changes: 20 additions & 0 deletions ProgramProject.Gateway/ProgramProject.Gateway.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<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" />
<PackageReference Include="Ocelot.Provider.Kubernetes" Version="24.1.0" />
<PackageReference Include="Ocelot.Provider.Polly" Version="24.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ProgramProject.ServiceDefaults\ProgramProject.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
41 changes: 41 additions & 0 deletions ProgramProject.Gateway/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:37101",
"sslPort": 44300
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5232",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7088;http://localhost:5232",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
8 changes: 8 additions & 0 deletions ProgramProject.Gateway/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions ProgramProject.Gateway/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
21 changes: 21 additions & 0 deletions ProgramProject.Gateway/ocelot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"Routes": [
{
"DownstreamPathTemplate": "/api/projects",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/api/projects",
"UpstreamHttpMethod": [ "GET" ],
"ServiceName": "generation-service",
"LoadBalancerOptions": {
"Type": "QueryBased",
"Key": "id"
}
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:5232",
"ServiceDiscoveryProvider": {
"Type": "AppHost"
}
}
}
34 changes: 34 additions & 0 deletions ProgramProject.GenerationService/Controllers/ProjectsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using ProgramProject.GenerationService.Models;
using ProgramProject.GenerationService.Services;

namespace ProgramProject.GenerationService.Controllers;

[Route("api/[controller]")]
[ApiController]
public class ProjectsController(IProjectService projectService, ILogger<ProjectsController> logger) : ControllerBase
{
[HttpGet]
[ProducesResponseType(typeof(ProgramProjectModel), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ProgramProjectModel>> GetProject([FromQuery] int id)
{
if (id <= 0)
{
return BadRequest("ID должен быть положительным числом");
}

try
{
logger.LogInformation("Запрос проекта с ID {ProjectId}", id);
var project = await projectService.GetProjectByIdAsync(id);
return Ok(project);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при обработке запроса проекта ID {ProjectId}", id);
return StatusCode(500, "Внутренняя ошибка сервера");
}
}
}
Loading