mirror of
https://github.com/Stone-Red-Code/RemoteExec.git
synced 2026-09-04 09:06:20 +02:00
Add source generator to generate ExecuteAsync overloads
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
namespace RemoteExec.Client.LoadBalancingStrategies;
|
namespace RemoteExec.Client.LoadBalancingStrategies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A load balancing strategy that selects servers based on local backlog.
|
||||||
|
/// </summary>
|
||||||
public class LeastBacklogStrategy : ILoadBalancingStrategy
|
public class LeastBacklogStrategy : ILoadBalancingStrategy
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
public ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers)
|
public ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers)
|
||||||
{
|
{
|
||||||
return availableServers.MinBy(s => s.TaskChannel.Reader.Count);
|
return availableServers.MinBy(s => s.TaskChannel.Reader.Count);
|
||||||
|
|||||||
@@ -16,4 +16,10 @@
|
|||||||
<ProjectReference Include="..\RemoteExec.Shared\RemoteExec.Shared.csproj" />
|
<ProjectReference Include="..\RemoteExec.Shared\RemoteExec.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\RemoteExec.Generators\RemoteExec.Generators.csproj"
|
||||||
|
OutputItemType="Analyzer"
|
||||||
|
ReferenceOutputAssembly="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace RemoteExec.Generators;
|
||||||
|
|
||||||
|
[Generator]
|
||||||
|
public class RemoteExecutorOverloadGenerator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
context.RegisterPostInitializationOutput(ctx =>
|
||||||
|
{
|
||||||
|
string source = GenerateOverloads(16);
|
||||||
|
ctx.AddSource("RemoteExecutor.Overloads.g.cs", SourceText.From(source, Encoding.UTF8));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateOverloads(int maxArgs)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
_ = sb.AppendLine("// <auto-generated />");
|
||||||
|
_ = sb.AppendLine("using System;");
|
||||||
|
_ = sb.AppendLine("using System.Threading;");
|
||||||
|
_ = sb.AppendLine("using System.Threading.Tasks;");
|
||||||
|
_ = sb.AppendLine();
|
||||||
|
_ = sb.AppendLine("namespace RemoteExec.Client;");
|
||||||
|
_ = sb.AppendLine();
|
||||||
|
_ = sb.AppendLine("public partial class RemoteExecutor");
|
||||||
|
_ = sb.AppendLine("{");
|
||||||
|
|
||||||
|
for (int i = 0; i <= maxArgs; i++)
|
||||||
|
{
|
||||||
|
// T1, T2, T3...
|
||||||
|
string typeParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n}"));
|
||||||
|
// T1 arg1, T2 arg2...
|
||||||
|
string methodParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n} arg{n}"));
|
||||||
|
// arg1, arg2...
|
||||||
|
string callArgs = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"arg{n}!"));
|
||||||
|
|
||||||
|
// Async overloads (Task<TResult>)
|
||||||
|
string genericBracket = i == 0 ? "<TResult>" : $"<{typeParams}, TResult>";
|
||||||
|
string funcType = i == 0 ? "Func<Task<TResult>>" : $"Func<{typeParams}, Task<TResult>>";
|
||||||
|
|
||||||
|
_ = sb.AppendLine($$"""
|
||||||
|
/// <summary>Generates a remote execution call for {{i}} async arguments.</summary>
|
||||||
|
public async Task<TResult> ExecuteAsync{{genericBracket}}(
|
||||||
|
{{funcType}} @delegate,
|
||||||
|
{{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
return await ExecuteAsync<{{funcType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}});
|
||||||
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
// Sync overloads (Func<TResult>)
|
||||||
|
string syncFuncType = i == 0 ? "Func<TResult>" : $"Func<{typeParams}, TResult>";
|
||||||
|
|
||||||
|
_ = sb.AppendLine($$"""
|
||||||
|
/// <summary>Generates a remote execution call for {{i}} synchronous arguments.</summary>
|
||||||
|
public async Task<TResult> ExecuteAsync{{genericBracket}}(
|
||||||
|
{{syncFuncType}} @delegate,
|
||||||
|
{{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
return await ExecuteAsync<{{syncFuncType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}});
|
||||||
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = sb.AppendLine("}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<Solution>
|
<Solution>
|
||||||
<Project Path="RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj" Id="e9895828-9e57-475e-98ea-2afff271b7e9" />
|
<Project Path="RemoteExec.Client.DependencyInjection/RemoteExec.Client.DependencyInjection.csproj" Id="e9895828-9e57-475e-98ea-2afff271b7e9" />
|
||||||
<Project Path="RemoteExec.Client/RemoteExec.Client.csproj" Id="8ac1533b-f69a-4b1b-bb3a-fb381cd4bb7b" />
|
<Project Path="RemoteExec.Client/RemoteExec.Client.csproj" Id="8ac1533b-f69a-4b1b-bb3a-fb381cd4bb7b" />
|
||||||
|
<Project Path="RemoteExec.Generators/RemoteExec.Generators.csproj" Id="71a394a7-22f4-4c59-b91f-744c48161696" />
|
||||||
<Project Path="RemoteExec.Server/RemoteExec.Server.csproj" Id="f88cb8bb-8221-4e5e-880a-0c58e1255602" />
|
<Project Path="RemoteExec.Server/RemoteExec.Server.csproj" Id="f88cb8bb-8221-4e5e-880a-0c58e1255602" />
|
||||||
<Project Path="RemoteExec.Shared/RemoteExec.Shared.csproj" Id="99317a9c-c0ad-42a2-a830-56aa9c6b9dd4" />
|
<Project Path="RemoteExec.Shared/RemoteExec.Shared.csproj" Id="99317a9c-c0ad-42a2-a830-56aa9c6b9dd4" />
|
||||||
<Project Path="RemoteExec/RemoteExec.Sample.csproj" />
|
<Project Path="RemoteExec/RemoteExec.Sample.csproj" />
|
||||||
|
|||||||
@@ -22,8 +22,11 @@ await singleHostExecutor.StartAsync();
|
|||||||
|
|
||||||
await Parallel.ForAsync(0, 1000, async (i, cancellationToken) =>
|
await Parallel.ForAsync(0, 1000, async (i, cancellationToken) =>
|
||||||
{
|
{
|
||||||
int r = await singleHostExecutor.ExecuteAsync<Func<int, int, Task<int>>, int>(Multiply, i, i + 1);
|
int r = await singleHostExecutor.ExecuteAsync(Multiply, i, i + 1, cancellationToken);
|
||||||
Console.WriteLine($"Multiply {i} * {i + 1} = {r}");
|
Console.WriteLine($"Multiply {i} * {i + 1} = {r}");
|
||||||
|
|
||||||
|
int s = await singleHostExecutor.ExecuteAsync(Add, i, i + 1, cancellationToken);
|
||||||
|
Console.WriteLine($"Add {i} + {i + 1} = {s}");
|
||||||
});
|
});
|
||||||
|
|
||||||
await singleHostExecutor.StopAsync();
|
await singleHostExecutor.StopAsync();
|
||||||
@@ -33,3 +36,8 @@ static async Task<int> Multiply(int x, int y)
|
|||||||
await Task.Delay(Random.Shared.Next(100, 500));
|
await Task.Delay(Random.Shared.Next(100, 500));
|
||||||
return x.Multiply(y);
|
return x.Multiply(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Add(int x, int y)
|
||||||
|
{
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user