mirror of
https://github.com/Stone-Red-Code/RemoteExec.git
synced 2026-09-05 07:46:32 +02:00
Add XML docs
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -4,8 +4,18 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace RemoteExec.Client.DependencyInjection;
|
namespace RemoteExec.Client.DependencyInjection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for registering RemoteExecutor with dependency injection.
|
||||||
|
/// </summary>
|
||||||
public static class RemoteExecutorServiceCollectionExtensions
|
public static class RemoteExecutorServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a singleton RemoteExecutor to the service collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to add to.</param>
|
||||||
|
/// <param name="urls">The URLs of the remote execution servers.</param>
|
||||||
|
/// <param name="configure">An optional action to configure the executor options.</param>
|
||||||
|
/// <returns>The service collection for chaining.</returns>
|
||||||
public static IServiceCollection AddRemoteExecutor(this IServiceCollection services, string[] urls, Action<RemoteExecutorOptions>? configure = null)
|
public static IServiceCollection AddRemoteExecutor(this IServiceCollection services, string[] urls, Action<RemoteExecutorOptions>? configure = null)
|
||||||
{
|
{
|
||||||
RemoteExecutorOptions options = new RemoteExecutorOptions();
|
RemoteExecutorOptions options = new RemoteExecutorOptions();
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An async-compatible manual reset event that can be awaited.
|
||||||
|
/// </summary>
|
||||||
internal class AsyncManualResetEvent
|
internal class AsyncManualResetEvent
|
||||||
{
|
{
|
||||||
private volatile TaskCompletionSource<bool> _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
private volatile TaskCompletionSource<bool> _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AsyncManualResetEvent"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initialState">If true, the event is initially signaled.</param>
|
||||||
public AsyncManualResetEvent(bool initialState)
|
public AsyncManualResetEvent(bool initialState)
|
||||||
{
|
{
|
||||||
if (initialState)
|
if (initialState)
|
||||||
@@ -12,16 +19,27 @@ internal class AsyncManualResetEvent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously waits for the event to be signaled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">A cancellation token to cancel the wait operation.</param>
|
||||||
|
/// <returns>A task that completes when the event is signaled.</returns>
|
||||||
public Task WaitAsync(CancellationToken ct)
|
public Task WaitAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
return _tcs.Task.WaitAsync(ct);
|
return _tcs.Task.WaitAsync(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the event to a signaled state, releasing all waiting tasks.
|
||||||
|
/// </summary>
|
||||||
public void Set()
|
public void Set()
|
||||||
{
|
{
|
||||||
_ = _tcs.TrySetResult(true);
|
_ = _tcs.TrySetResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the event to an unsignaled state.
|
||||||
|
/// </summary>
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
namespace RemoteExec.Client.Exceptions;
|
namespace RemoteExec.Client.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when a task exceeds the maximum number of retry attempts.
|
||||||
|
/// </summary>
|
||||||
public class MaxRetriesException(string message) : Exception(message)
|
public class MaxRetriesException(string message) : Exception(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
namespace RemoteExec.Client.Exceptions;
|
namespace RemoteExec.Client.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when a remote method execution fails on the server.
|
||||||
|
/// </summary>
|
||||||
public class RemoteExecutionException(string message) : Exception(message)
|
public class RemoteExecutionException(string message) : Exception(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a strategy for selecting a server from a pool of available servers for task distribution.
|
||||||
|
/// </summary>
|
||||||
public interface ILoadBalancingStrategy
|
public interface ILoadBalancingStrategy
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Selects the most appropriate server from the available servers based on the strategy's logic.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="availableServers">The collection of available servers to choose from.</param>
|
||||||
|
/// <returns>The selected server, or <c>null</c> if no suitable server is found.</returns>
|
||||||
ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers);
|
ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
namespace RemoteExec.Client.LoadBalancingStrategies;
|
namespace RemoteExec.Client.LoadBalancingStrategies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A load balancing strategy that selects servers based on CPU usage, active tasks, and backlog.
|
||||||
|
/// </summary>
|
||||||
internal class ResourceAwareStrategy : ILoadBalancingStrategy
|
internal class ResourceAwareStrategy : ILoadBalancingStrategy
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
public ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers)
|
public ServerConnection? SelectServer(IEnumerable<ServerConnection> availableServers)
|
||||||
{
|
{
|
||||||
return availableServers.MinBy(s =>
|
return availableServers.MinBy(s =>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,21 +2,33 @@
|
|||||||
|
|
||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logger provider that forwards log messages to an existing logger instance.
|
||||||
|
/// </summary>
|
||||||
internal class RemoteExecLoggerProvider : ILoggerProvider
|
internal class RemoteExecLoggerProvider : ILoggerProvider
|
||||||
{
|
{
|
||||||
private bool disposedValue;
|
private bool disposedValue;
|
||||||
private readonly ILogger logger;
|
private readonly ILogger logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecLoggerProvider"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">The logger instance to forward messages to.</param>
|
||||||
public RemoteExecLoggerProvider(ILogger logger)
|
public RemoteExecLoggerProvider(ILogger logger)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public ILogger CreateLogger(string categoryName)
|
public ILogger CreateLogger(string categoryName)
|
||||||
{
|
{
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes the logger provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">True if disposing managed resources.</param>
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposedValue)
|
if (!disposedValue)
|
||||||
@@ -26,6 +38,7 @@ internal class RemoteExecLoggerProvider : ILoggerProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(disposing: true);
|
Dispose(disposing: true);
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ namespace RemoteExec.Client;
|
|||||||
|
|
||||||
public partial class RemoteExecutor
|
public partial class RemoteExecutor
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the remote executor, connecting to all configured servers and beginning task distribution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
|
||||||
public async Task StartAsync(CancellationToken cancellationToken = default)
|
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
// Dispose previous cancellation token source if exists
|
// Dispose previous cancellation token source if exists
|
||||||
@@ -40,6 +44,10 @@ public partial class RemoteExecutor
|
|||||||
distributorTask = Task.Run(() => DistributorLoop(distributorCts.Token), distributorCts.Token);
|
distributorTask = Task.Run(() => DistributorLoop(distributorCts.Token), distributorCts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the remote executor, disconnecting from all servers and stopping task distribution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
|
||||||
public async Task StopAsync(CancellationToken cancellationToken = default)
|
public async Task StopAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Stopping RemoteExecutor...");
|
logger.LogInformation("Stopping RemoteExecutor...");
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ using System.Text.Json;
|
|||||||
|
|
||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages remote execution of static methods across one or more server connections with load balancing and fault tolerance.
|
||||||
|
/// </summary>
|
||||||
public partial class RemoteExecutor : IAsyncDisposable
|
public partial class RemoteExecutor : IAsyncDisposable
|
||||||
{
|
{
|
||||||
private readonly BlockingCollection<PendingTask> globalQueue;
|
private readonly BlockingCollection<PendingTask> globalQueue;
|
||||||
@@ -27,20 +30,45 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
|
|
||||||
private bool disposedValue;
|
private bool disposedValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when server metrics are updated.
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<ServerMetricsUpdatedEventArgs>? MetricsUpdated;
|
public event EventHandler<ServerMetricsUpdatedEventArgs>? MetricsUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutor"/> class with a single server URL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The URL of the remote server.</param>
|
||||||
|
/// <param name="configure">An action to configure the executor options.</param>
|
||||||
public RemoteExecutor(string url, Action<RemoteExecutorOptions> configure) : this([url], NullLogger.Instance, configure)
|
public RemoteExecutor(string url, Action<RemoteExecutorOptions> configure) : this([url], NullLogger.Instance, configure)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutor"/> class with a single server URL and logger.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The URL of the remote server.</param>
|
||||||
|
/// <param name="logger">The logger instance.</param>
|
||||||
|
/// <param name="configure">An action to configure the executor options.</param>
|
||||||
public RemoteExecutor(string url, ILogger logger, Action<RemoteExecutorOptions> configure) : this([url], logger, configure)
|
public RemoteExecutor(string url, ILogger logger, Action<RemoteExecutorOptions> configure) : this([url], logger, configure)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutor"/> class with multiple server URLs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urls">The URLs of the remote servers.</param>
|
||||||
|
/// <param name="configure">An action to configure the executor options.</param>
|
||||||
public RemoteExecutor(string[] urls, Action<RemoteExecutorOptions> configure) : this(urls, NullLogger.Instance, configure)
|
public RemoteExecutor(string[] urls, Action<RemoteExecutorOptions> configure) : this(urls, NullLogger.Instance, configure)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutor"/> class with multiple server URLs and logger.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urls">The URLs of the remote servers.</param>
|
||||||
|
/// <param name="logger">The logger instance.</param>
|
||||||
|
/// <param name="configure">An action to configure the executor options.</param>
|
||||||
public RemoteExecutor(string[] urls, ILogger logger, Action<RemoteExecutorOptions> configure)
|
public RemoteExecutor(string[] urls, ILogger logger, Action<RemoteExecutorOptions> configure)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -53,6 +81,12 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
InitializeServers(urls);
|
InitializeServers(urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutor"/> class with preconfigured options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urls">The URLs of the remote servers.</param>
|
||||||
|
/// <param name="options">The executor options.</param>
|
||||||
|
/// <param name="logger">The logger instance.</param>
|
||||||
public RemoteExecutor(string[] urls, RemoteExecutorOptions options, ILogger logger)
|
public RemoteExecutor(string[] urls, RemoteExecutorOptions options, ILogger logger)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -99,6 +133,10 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current metrics for all connected servers.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A dictionary mapping server IDs to their metrics.</returns>
|
||||||
public Dictionary<string, ServerMetrics> GetCurrentServerMetrics()
|
public Dictionary<string, ServerMetrics> GetCurrentServerMetrics()
|
||||||
{
|
{
|
||||||
return servers
|
return servers
|
||||||
@@ -107,6 +145,15 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
.ToDictionary(metrics => metrics!.ServerId, metrics => metrics!);
|
.ToDictionary(metrics => metrics!.ServerId, metrics => metrics!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a delegate remotely and returns the strongly-typed result.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TDelegate">The delegate type.</typeparam>
|
||||||
|
/// <typeparam name="TResult">The return type.</typeparam>
|
||||||
|
/// <param name="delegate">The delegate to execute.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
|
||||||
|
/// <param name="args">The arguments to pass to the method.</param>
|
||||||
|
/// <returns>The result of the remote execution.</returns>
|
||||||
public async Task<TResult> ExecuteAsync<TDelegate, TResult>(TDelegate @delegate, CancellationToken cancellationToken, params object[] args) where TDelegate : Delegate
|
public async Task<TResult> ExecuteAsync<TDelegate, TResult>(TDelegate @delegate, CancellationToken cancellationToken, params object[] args) where TDelegate : Delegate
|
||||||
{
|
{
|
||||||
object? execResult = await ExecuteAsync(@delegate, cancellationToken, args);
|
object? execResult = await ExecuteAsync(@delegate, cancellationToken, args);
|
||||||
@@ -125,11 +172,29 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a delegate remotely and returns the strongly-typed result.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TDelegate">The delegate type.</typeparam>
|
||||||
|
/// <typeparam name="TResult">The return type.</typeparam>
|
||||||
|
/// <param name="delegate">The delegate to execute.</param>
|
||||||
|
/// <param name="args">The arguments to pass to the method.</param>
|
||||||
|
/// <returns>The result of the remote execution.</returns>
|
||||||
public async Task<TResult> ExecuteAsync<TDelegate, TResult>(TDelegate @delegate, params object[] args) where TDelegate : Delegate
|
public async Task<TResult> ExecuteAsync<TDelegate, TResult>(TDelegate @delegate, params object[] args) where TDelegate : Delegate
|
||||||
{
|
{
|
||||||
return await ExecuteAsync<TDelegate, TResult>(@delegate, CancellationToken.None, args);
|
return await ExecuteAsync<TDelegate, TResult>(@delegate, CancellationToken.None, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a delegate remotely and returns the result.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The delegate type.</typeparam>
|
||||||
|
/// <param name="delegate">The delegate to execute. Must be a static method.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
|
||||||
|
/// <param name="args">The arguments to pass to the method.</param>
|
||||||
|
/// <returns>The result of the remote execution.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when the delegate is not a static method or uses a dynamic assembly.</exception>
|
||||||
|
/// <exception cref="RemoteExecutionException">Thrown when the remote execution fails.</exception>
|
||||||
public async Task<object?> ExecuteAsync<T>(T @delegate, CancellationToken cancellationToken, params object[] args) where T : Delegate
|
public async Task<object?> ExecuteAsync<T>(T @delegate, CancellationToken cancellationToken, params object[] args) where T : Delegate
|
||||||
{
|
{
|
||||||
MethodInfo method = @delegate.Method;
|
MethodInfo method = @delegate.Method;
|
||||||
@@ -189,11 +254,22 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a delegate remotely and returns the result.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The delegate type.</typeparam>
|
||||||
|
/// <param name="delegate">The delegate to execute. Must be a static method.</param>
|
||||||
|
/// <param name="args">The arguments to pass to the method.</param>
|
||||||
|
/// <returns>The result of the remote execution.</returns>
|
||||||
public Task<object?> ExecuteAsync<T>(T @delegate, params object[] args) where T : Delegate
|
public Task<object?> ExecuteAsync<T>(T @delegate, params object[] args) where T : Delegate
|
||||||
{
|
{
|
||||||
return ExecuteAsync(@delegate, CancellationToken.None, args);
|
return ExecuteAsync(@delegate, CancellationToken.None, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously disposes the executor and its resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">True if disposing managed resources.</param>
|
||||||
protected virtual async Task DisposeAsync(bool disposing)
|
protected virtual async Task DisposeAsync(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposedValue)
|
if (!disposedValue)
|
||||||
@@ -220,6 +296,7 @@ public partial class RemoteExecutor : IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
await DisposeAsync(disposing: true);
|
await DisposeAsync(disposing: true);
|
||||||
|
|||||||
@@ -2,22 +2,49 @@
|
|||||||
|
|
||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration options for the remote executor client.
|
||||||
|
/// </summary>
|
||||||
public class RemoteExecutorOptions
|
public class RemoteExecutorOptions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the load balancing strategy used to select servers for task execution.
|
||||||
|
/// Default is <see cref="ResourceAwareStrategy"/>.
|
||||||
|
/// </summary>
|
||||||
public ILoadBalancingStrategy Strategy { get; set; } = new ResourceAwareStrategy();
|
public ILoadBalancingStrategy Strategy { get; set; } = new ResourceAwareStrategy();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the API key used for authenticating with remote servers.
|
||||||
|
/// </summary>
|
||||||
public string ApiKey { get; set; } = string.Empty;
|
public string ApiKey { get; set; } = string.Empty;
|
||||||
|
|
||||||
// How long to wait for a result before throwing a TimeoutException
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum time to wait for a task result before throwing a TimeoutException.
|
||||||
|
/// Default is 5 minutes.
|
||||||
|
/// </summary>
|
||||||
public TimeSpan ExecutionTimeout { get; set; } = TimeSpan.FromMinutes(5);
|
public TimeSpan ExecutionTimeout { get; set; } = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
// Backoff settings for server reconnections
|
/// <summary>
|
||||||
|
/// Gets or sets the initial delay before attempting to reconnect to a disconnected server.
|
||||||
|
/// Default is 5 seconds.
|
||||||
|
/// </summary>
|
||||||
public TimeSpan ServerReconnectInitialDelay { get; set; } = TimeSpan.FromSeconds(5);
|
public TimeSpan ServerReconnectInitialDelay { get; set; } = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum delay between server reconnection attempts.
|
||||||
|
/// Default is 60 seconds.
|
||||||
|
/// </summary>
|
||||||
public TimeSpan ServerReconnectMaxDelay { get; set; } = TimeSpan.FromSeconds(60);
|
public TimeSpan ServerReconnectMaxDelay { get; set; } = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
// Reliability: How many times a task can be requeued before failing
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum number of times a failed task can be requeued before failing permanently.
|
||||||
|
/// Default is 3.
|
||||||
|
/// </summary>
|
||||||
public int MaxTaskRetries { get; set; } = 3;
|
public int MaxTaskRetries { get; set; } = 3;
|
||||||
|
|
||||||
// Capacity: Stop accepting Execute calls if the global queue is too full
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum number of tasks that can be queued globally before blocking new execute calls.
|
||||||
|
/// Default is 1000.
|
||||||
|
/// </summary>
|
||||||
public int GlobalQueueCapacity { get; set; } = 1000;
|
public int GlobalQueueCapacity { get; set; } = 1000;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,33 @@ using System.Threading.Channels;
|
|||||||
|
|
||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a connection to a remote execution server, including communication channels and metrics.
|
||||||
|
/// </summary>
|
||||||
public class ServerConnection(HubConnection connection, HttpClient httpClient)
|
public class ServerConnection(HubConnection connection, HttpClient httpClient)
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SignalR hub connection to the server.
|
||||||
|
/// </summary>
|
||||||
public HubConnection Connection { get; } = connection;
|
public HubConnection Connection { get; } = connection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HTTP client for REST API communication with the server.
|
||||||
|
/// </summary>
|
||||||
public HttpClient HttpClient { get; } = httpClient;
|
public HttpClient HttpClient { get; } = httpClient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel used to queue tasks for this server.
|
||||||
|
/// </summary>
|
||||||
public Channel<TaskItem> TaskChannel { get; } = Channel.CreateUnbounded<TaskItem>();
|
public Channel<TaskItem> TaskChannel { get; } = Channel.CreateUnbounded<TaskItem>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current metrics for this server.
|
||||||
|
/// </summary>
|
||||||
public ServerMetrics? Metrics { get; set; }
|
public ServerMetrics? Metrics { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler for connection closed events.
|
||||||
|
/// </summary>
|
||||||
public Func<Exception?, Task>? ClosedEventHandler { get; set; }
|
public Func<Exception?, Task>? ClosedEventHandler { get; set; }
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,18 @@ using RemoteExec.Shared;
|
|||||||
|
|
||||||
namespace RemoteExec.Client;
|
namespace RemoteExec.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides data for the <see cref="RemoteExecutor.MetricsUpdated"/> event.
|
||||||
|
/// </summary>
|
||||||
public class ServerMetricsUpdatedEventArgs(HubConnection connection, ServerMetrics metrics) : EventArgs
|
public class ServerMetricsUpdatedEventArgs(HubConnection connection, ServerMetrics metrics) : EventArgs
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the hub connection associated with the metrics update.
|
||||||
|
/// </summary>
|
||||||
public HubConnection Connection { get; } = connection;
|
public HubConnection Connection { get; } = connection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the updated server metrics.
|
||||||
|
/// </summary>
|
||||||
public ServerMetrics Metrics { get; } = metrics;
|
public ServerMetrics Metrics { get; } = metrics;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,23 @@
|
|||||||
namespace RemoteExec.Server.Configuration;
|
namespace RemoteExec.Server.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an individual API key configuration.
|
||||||
|
/// </summary>
|
||||||
public class ApiKeyConfiguration
|
public class ApiKeyConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the API key value.
|
||||||
|
/// </summary>
|
||||||
public required string Key { get; set; }
|
public required string Key { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an optional description of the API key.
|
||||||
|
/// </summary>
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether this API key is enabled.
|
||||||
|
/// Default is true.
|
||||||
|
/// </summary>
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
namespace RemoteExec.Server.Configuration;
|
namespace RemoteExec.Server.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration for API key authentication.
|
||||||
|
/// </summary>
|
||||||
public class AuthenticationConfiguration
|
public class AuthenticationConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the list of configured API keys.
|
||||||
|
/// </summary>
|
||||||
public List<ApiKeyConfiguration> ApiKeys { get; set; } = [];
|
public List<ApiKeyConfiguration> ApiKeys { get; set; } = [];
|
||||||
}
|
}
|
||||||
@@ -4,10 +4,18 @@ using RemoteExec.Server.Hubs;
|
|||||||
|
|
||||||
namespace RemoteExec.Server.Controllers;
|
namespace RemoteExec.Server.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controller for handling assembly upload requests from clients.
|
||||||
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/")]
|
[Route("/")]
|
||||||
public class AssemblyController(ILogger<AssemblyController> logger) : ControllerBase
|
public class AssemblyController(ILogger<AssemblyController> logger) : ControllerBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Receives an assembly binary from a client in response to an assembly request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestId">The unique identifier for the assembly request.</param>
|
||||||
|
/// <returns>An action result indicating success or failure.</returns>
|
||||||
[HttpPost("provide-assembly")]
|
[HttpPost("provide-assembly")]
|
||||||
public async Task<IActionResult> ProvideAssembly([FromQuery] Guid requestId)
|
public async Task<IActionResult> ProvideAssembly([FromQuery] Guid requestId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ using System.Text.Json;
|
|||||||
|
|
||||||
namespace RemoteExec.Server.Hubs;
|
namespace RemoteExec.Server.Hubs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SignalR hub that handles remote method execution requests from clients.
|
||||||
|
/// </summary>
|
||||||
public class RemoteExecutionHub : Hub
|
public class RemoteExecutionHub : Hub
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, RemoteJobAssemblyLoadContext> connections = new();
|
private static readonly ConcurrentDictionary<string, RemoteJobAssemblyLoadContext> connections = new();
|
||||||
@@ -34,6 +37,12 @@ public class RemoteExecutionHub : Hub
|
|||||||
|
|
||||||
private readonly ILogger<RemoteExecutionHub> logger;
|
private readonly ILogger<RemoteExecutionHub> logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RemoteExecutionHub"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">The logger instance.</param>
|
||||||
|
/// <param name="executionOptions">The execution configuration options.</param>
|
||||||
|
/// <param name="metricsOptions">The metrics configuration options.</param>
|
||||||
public RemoteExecutionHub(ILogger<RemoteExecutionHub> logger, IOptions<ExecutionConfiguration> executionOptions, IOptions<MetricsConfiguration> metricsOptions)
|
public RemoteExecutionHub(ILogger<RemoteExecutionHub> logger, IOptions<ExecutionConfiguration> executionOptions, IOptions<MetricsConfiguration> metricsOptions)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -49,6 +58,7 @@ public class RemoteExecutionHub : Hub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override Task OnConnectedAsync()
|
public override Task OnConnectedAsync()
|
||||||
{
|
{
|
||||||
RemoteJobAssemblyLoadContext assemblyLoadContext = new RemoteJobAssemblyLoadContext($"RemoteJob_{Guid.NewGuid()}");
|
RemoteJobAssemblyLoadContext assemblyLoadContext = new RemoteJobAssemblyLoadContext($"RemoteJob_{Guid.NewGuid()}");
|
||||||
@@ -61,6 +71,7 @@ public class RemoteExecutionHub : Hub
|
|||||||
return base.OnConnectedAsync();
|
return base.OnConnectedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public override Task OnDisconnectedAsync(Exception? exception)
|
public override Task OnDisconnectedAsync(Exception? exception)
|
||||||
{
|
{
|
||||||
if (connections.TryRemove(Context.ConnectionId, out RemoteJobAssemblyLoadContext? assemblyLoadContext))
|
if (connections.TryRemove(Context.ConnectionId, out RemoteJobAssemblyLoadContext? assemblyLoadContext))
|
||||||
@@ -74,6 +85,10 @@ public class RemoteExecutionHub : Hub
|
|||||||
return base.OnDisconnectedAsync(exception);
|
return base.OnDisconnectedAsync(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts processing a stream of tasks from the client.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskStream">The async enumerable stream of tasks to execute.</param>
|
||||||
public async Task StartTaskStream(IAsyncEnumerable<TaskItem> taskStream)
|
public async Task StartTaskStream(IAsyncEnumerable<TaskItem> taskStream)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Starting task stream for connection {ConnectionId}", Context.ConnectionId);
|
logger.LogInformation("Starting task stream for connection {ConnectionId}", Context.ConnectionId);
|
||||||
@@ -119,6 +134,11 @@ public class RemoteExecutionHub : Hub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a single remote method request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="req">The execution request.</param>
|
||||||
|
/// <returns>The execution result.</returns>
|
||||||
public async Task<RemoteExecutionResult> Execute(RemoteExecutionRequest req)
|
public async Task<RemoteExecutionResult> Execute(RemoteExecutionRequest req)
|
||||||
{
|
{
|
||||||
return await ExecuteTask(req);
|
return await ExecuteTask(req);
|
||||||
@@ -231,6 +251,11 @@ public class RemoteExecutionHub : Hub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides assembly bytes to fulfill a pending assembly request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestId">The unique identifier for the assembly request.</param>
|
||||||
|
/// <param name="assemblyBytes">The assembly binary data.</param>
|
||||||
public static async Task ProvideAssembly(Guid requestId, byte[] assemblyBytes)
|
public static async Task ProvideAssembly(Guid requestId, byte[] assemblyBytes)
|
||||||
{
|
{
|
||||||
if (pendingAssemblyRequests.TryRemove(requestId, out TaskCompletionSource<byte[]>? tcs))
|
if (pendingAssemblyRequests.TryRemove(requestId, out TaskCompletionSource<byte[]>? tcs))
|
||||||
@@ -239,11 +264,19 @@ public class RemoteExecutionHub : Hub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current server metrics.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The current server metrics.</returns>
|
||||||
public async Task<ServerMetrics> GetMetrics()
|
public async Task<ServerMetrics> GetMetrics()
|
||||||
{
|
{
|
||||||
return await GetServerMetrics();
|
return await GetServerMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcasts server metrics to all connected clients if metrics have changed significantly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hubContext">The hub context for broadcasting.</param>
|
||||||
public static async Task BroadcastMetricsAsync(IHubContext<RemoteExecutionHub> hubContext)
|
public static async Task BroadcastMetricsAsync(IHubContext<RemoteExecutionHub> hubContext)
|
||||||
{
|
{
|
||||||
ServerMetrics metrics = await GetServerMetrics();
|
ServerMetrics metrics = await GetServerMetrics();
|
||||||
|
|||||||
@@ -7,12 +7,21 @@ using System.Collections.Concurrent;
|
|||||||
|
|
||||||
namespace RemoteExec.Server.Middleware;
|
namespace RemoteExec.Server.Middleware;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Middleware that authenticates requests using API keys in the X-API-Key header.
|
||||||
|
/// </summary>
|
||||||
public class ApiKeyAuthenticationMiddleware
|
public class ApiKeyAuthenticationMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly ILogger<ApiKeyAuthenticationMiddleware> _logger;
|
private readonly ILogger<ApiKeyAuthenticationMiddleware> _logger;
|
||||||
private readonly ConcurrentDictionary<string, ApiKeyConfiguration> _apiKeys;
|
private readonly ConcurrentDictionary<string, ApiKeyConfiguration> _apiKeys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ApiKeyAuthenticationMiddleware"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="next">The next middleware in the pipeline.</param>
|
||||||
|
/// <param name="authOptions">The authentication configuration options.</param>
|
||||||
|
/// <param name="logger">The logger instance.</param>
|
||||||
public ApiKeyAuthenticationMiddleware(
|
public ApiKeyAuthenticationMiddleware(
|
||||||
RequestDelegate next,
|
RequestDelegate next,
|
||||||
IOptionsMonitor<AuthenticationConfiguration> authOptions,
|
IOptionsMonitor<AuthenticationConfiguration> authOptions,
|
||||||
@@ -66,6 +75,10 @@ public class ApiKeyAuthenticationMiddleware
|
|||||||
_logger.LogInformation("Loaded {Count} active API keys", _apiKeys.Count);
|
_logger.LogInformation("Loaded {Count} active API keys", _apiKeys.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the middleware to authenticate the request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The HTTP context for the current request.</param>
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
// Skip authentication for health checks
|
// Skip authentication for health checks
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace RemoteExec.Server;
|
namespace RemoteExec.Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An isolated assembly load context for remote job execution, allowing assemblies to be unloaded.
|
||||||
|
/// </summary>
|
||||||
public class RemoteJobAssemblyLoadContext(string name) : AssemblyLoadContext(name, true)
|
public class RemoteJobAssemblyLoadContext(string name) : AssemblyLoadContext(name, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,34 @@
|
|||||||
|
|
||||||
namespace RemoteExec.Server;
|
namespace RemoteExec.Server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event arguments for assembly request events.
|
||||||
|
/// </summary>
|
||||||
public class RequestAssemblyEventArgs(AssemblyName assemblyName) : EventArgs
|
public class RequestAssemblyEventArgs(AssemblyName assemblyName) : EventArgs
|
||||||
{
|
{
|
||||||
private readonly TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
|
private readonly TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
|
||||||
|
|
||||||
private Assembly? assembly = null;
|
private Assembly? assembly = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the assembly name being requested.
|
||||||
|
/// </summary>
|
||||||
public AssemblyName Assembly { get; } = assemblyName;
|
public AssemblyName Assembly { get; } = assemblyName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously waits for the assembly to be provided.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The assembly, or null if not provided.</returns>
|
||||||
public async Task<Assembly?> GetAssemblyAsync()
|
public async Task<Assembly?> GetAssemblyAsync()
|
||||||
{
|
{
|
||||||
await taskCompletionSource.Task;
|
await taskCompletionSource.Task;
|
||||||
return assembly;
|
return assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the assembly to fulfill the request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly">The assembly to provide.</param>
|
||||||
public void SetAssembly(Assembly assembly)
|
public void SetAssembly(Assembly assembly)
|
||||||
{
|
{
|
||||||
this.assembly = assembly;
|
this.assembly = assembly;
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ using RemoteExec.Server.Hubs;
|
|||||||
|
|
||||||
namespace RemoteExec.Server.Services;
|
namespace RemoteExec.Server.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Background service that periodically broadcasts server metrics to all connected clients.
|
||||||
|
/// </summary>
|
||||||
public class MetricsBroadcastService(IHubContext<RemoteExecutionHub> hubContext, ILogger<MetricsBroadcastService> logger, IOptions<MetricsConfiguration> metricsOptions) : BackgroundService
|
public class MetricsBroadcastService(IHubContext<RemoteExecutionHub> hubContext, ILogger<MetricsBroadcastService> logger, IOptions<MetricsConfiguration> metricsOptions) : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly TimeSpan broadcastInterval = TimeSpan.FromMilliseconds(metricsOptions.Value.BroadcastIntervalMs);
|
private readonly TimeSpan broadcastInterval = TimeSpan.FromMilliseconds(metricsOptions.Value.BroadcastIntervalMs);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Metrics broadcast service started with interval {Interval}ms", broadcastInterval.TotalMilliseconds);
|
logger.LogInformation("Metrics broadcast service started with interval {Interval}ms", broadcastInterval.TotalMilliseconds);
|
||||||
|
|||||||
@@ -1,10 +1,32 @@
|
|||||||
namespace RemoteExec.Shared;
|
namespace RemoteExec.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a request to execute a static method on a remote server.
|
||||||
|
/// </summary>
|
||||||
public sealed class RemoteExecutionRequest
|
public sealed class RemoteExecutionRequest
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the full name of the assembly containing the method.
|
||||||
|
/// </summary>
|
||||||
public required string AssemblyName { get; set; }
|
public required string AssemblyName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the full name of the type containing the method.
|
||||||
|
/// </summary>
|
||||||
public required string TypeName { get; set; }
|
public required string TypeName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the method to execute.
|
||||||
|
/// </summary>
|
||||||
public required string MethodName { get; set; }
|
public required string MethodName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the assembly-qualified names of the method's parameter types.
|
||||||
|
/// </summary>
|
||||||
public required string[] ArgumentTypes { get; set; }
|
public required string[] ArgumentTypes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the arguments to pass to the method.
|
||||||
|
/// </summary>
|
||||||
public required object[] Arguments { get; set; }
|
public required object[] Arguments { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
namespace RemoteExec.Shared;
|
namespace RemoteExec.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the result of a remote method execution.
|
||||||
|
/// </summary>
|
||||||
public sealed class RemoteExecutionResult
|
public sealed class RemoteExecutionResult
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the return value of the executed method, or null if the method returns void.
|
||||||
|
/// </summary>
|
||||||
public object? Result { get; set; }
|
public object? Result { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the exception message if the execution failed, or null if successful.
|
||||||
|
/// </summary>
|
||||||
public string? Exception { get; set; }
|
public string? Exception { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,42 @@
|
|||||||
namespace RemoteExec.Shared;
|
namespace RemoteExec.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents performance and status metrics for a remote execution server.
|
||||||
|
/// </summary>
|
||||||
public sealed class ServerMetrics
|
public sealed class ServerMetrics
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the number of active client connections to the server.
|
||||||
|
/// </summary>
|
||||||
public int ActiveConnections { get; set; }
|
public int ActiveConnections { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the number of tasks currently being executed on the server.
|
||||||
|
/// </summary>
|
||||||
public int ActiveTasks { get; set; }
|
public int ActiveTasks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum number of tasks that can execute concurrently on the server.
|
||||||
|
/// </summary>
|
||||||
public int MaxConcurrentTasks { get; set; }
|
public int MaxConcurrentTasks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the total memory usage of the server process in bytes.
|
||||||
|
/// </summary>
|
||||||
public long TotalMemoryUsage { get; set; }
|
public long TotalMemoryUsage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CPU usage percentage (0-100) of the server process.
|
||||||
|
/// </summary>
|
||||||
public double CpuUsage { get; set; }
|
public double CpuUsage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the timestamp when these metrics were captured.
|
||||||
|
/// </summary>
|
||||||
public DateTime Timestamp { get; set; }
|
public DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the unique identifier for the server.
|
||||||
|
/// </summary>
|
||||||
public string ServerId { get; set; } = string.Empty;
|
public string ServerId { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,17 @@
|
|||||||
namespace RemoteExec.Shared;
|
namespace RemoteExec.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a task item in the execution stream, combining a task ID with its execution request.
|
||||||
|
/// </summary>
|
||||||
public class TaskItem
|
public class TaskItem
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the unique identifier for this task.
|
||||||
|
/// </summary>
|
||||||
public Guid TaskId { get; set; }
|
public Guid TaskId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the execution request details.
|
||||||
|
/// </summary>
|
||||||
public required RemoteExecutionRequest Request { get; set; }
|
public required RemoteExecutionRequest Request { get; set; }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user