Add Role based grain placement

This commit is contained in:
2025-09-18 20:17:28 +07:00
parent 530dd83daa
commit c2f3734021
16 changed files with 404 additions and 18 deletions

View File

@@ -0,0 +1,151 @@
using Orleans.Runtime.Placement;
namespace Managing.Application.Orleans;
/// <summary>
/// Placement strategy for compute-intensive grains (Genetic Backtest, Bundle Backtest)
/// These grains should be placed on servers with the "Compute" role
/// </summary>
[Serializable]
public sealed class ComputePlacementStrategy : PlacementStrategy
{
}
/// <summary>
/// Placement strategy for trading grains (Live Trading Bots, Agent Grains)
/// These grains should be placed on servers with the "Trading" role
/// Uses activation-count-based placement for load balancing across multiple trading silos
/// </summary>
[Serializable]
public sealed class TradingPlacementStrategy : PlacementStrategy
{
}
/// <summary>
/// Placement attribute for compute-intensive grains
/// Uses custom placement strategy with random fallback
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ComputePlacementAttribute : Attribute
{
}
/// <summary>
/// Placement attribute for trading grains with load balancing
/// Uses custom placement strategy with activation-count-based fallback
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class TradingPlacementAttribute : Attribute
{
}
/// <summary>
/// Placement director for compute-intensive grains
/// Places grains on silos with the "Compute" role, falls back to random placement
/// </summary>
public class ComputePlacementDirector : IPlacementDirector
{
public Task<SiloAddress> OnAddActivation(
PlacementStrategy strategy,
PlacementTarget target,
IPlacementContext context)
{
var compatibleSilos = context.GetCompatibleSilos(target).ToList();
if (!compatibleSilos.Any())
{
throw new InvalidOperationException(
$"No compatible silos available for compute grain {target.GrainIdentity}");
}
// Try to find silos with "Compute" role by checking silo names
var computeSilos = compatibleSilos.Where(silo =>
{
// Check if silo name contains "-Compute" to identify compute silos
var siloName = GetSiloName(silo);
return siloName?.Contains("-Compute") == true;
}).ToList();
if (computeSilos.Any())
{
// Use random selection among compute silos
var random = new Random();
return Task.FromResult(computeSilos[random.Next(computeSilos.Count)]);
}
// Fallback: Use random placement among all compatible silos
var randomFallback = new Random();
return Task.FromResult(compatibleSilos[randomFallback.Next(compatibleSilos.Count)]);
}
private string GetSiloName(SiloAddress siloAddress)
{
// Extract silo name from the address - this is a simplified approach
// In a real implementation, you might need to access silo metadata differently
return siloAddress.ToString();
}
}
/// <summary>
/// Placement director for trading grains with load balancing
/// Places grains on silos with the "Trading" role using activation-count-based placement
/// Falls back to activation-count-based placement if no trading silos found
/// </summary>
public class TradingPlacementDirector : IPlacementDirector
{
public Task<SiloAddress> OnAddActivation(
PlacementStrategy strategy,
PlacementTarget target,
IPlacementContext context)
{
var compatibleSilos = context.GetCompatibleSilos(target).ToList();
if (!compatibleSilos.Any())
{
throw new InvalidOperationException(
$"No compatible silos available for trading grain {target.GrainIdentity}");
}
// Try to find silos with "Trading" role by checking silo names
var tradingSilos = compatibleSilos.Where(silo =>
{
// Check if silo name contains "-Trading" to identify trading silos
var siloName = GetSiloName(silo);
return siloName?.Contains("-Trading") == true;
}).ToList();
if (tradingSilos.Any())
{
// Use activation-count-based placement among trading silos
return SelectSiloWithLoadBalancing(tradingSilos, context);
}
// Fallback: Use activation-count-based placement among all compatible silos
return SelectSiloWithLoadBalancing(compatibleSilos, context);
}
private Task<SiloAddress> SelectSiloWithLoadBalancing(List<SiloAddress> silos, IPlacementContext context)
{
if (silos.Count == 1)
{
return Task.FromResult(silos.First());
}
// Implement "Power of Two Choices" algorithm for load balancing
var random = new Random();
var selectedSilos = silos.OrderBy(x => random.Next()).Take(2).ToList();
// For now, use random selection between the two chosen silos
// In a real implementation, you would check activation counts
var selectedSilo = selectedSilos[random.Next(selectedSilos.Count)];
return Task.FromResult(selectedSilo);
}
private string GetSiloName(SiloAddress siloAddress)
{
// Extract silo name from the address - this is a simplified approach
// In a real implementation, you might need to access silo metadata differently
return siloAddress.ToString();
}
}