Add Role based grain placement
This commit is contained in:
151
src/Managing.Application/Orleans/PlacementStrategy.cs
Normal file
151
src/Managing.Application/Orleans/PlacementStrategy.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user