[ 
https://issues.apache.org/jira/browse/IGNITE-22349?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Alexey Kukushkin updated IGNITE-22349:
--------------------------------------
    Description: 
We want Apache Ignite to support [priority 
ordering|https://ignite.apache.org/docs/latest/distributed-computing/job-scheduling#priority-ordering]
 of Ignite.NET compute jobs on the same node.

h4. Analysis

{{PriorityQueueCollisionSpi}} does priority ordering. The problem is the 
{{PriorityQueueCollisionSpi}} expects the user to provide job priorities 
via the {{ComputeTaskSession}}'s "{{grid.task.priority}}" attribute and the 
{{ComputeTaskSession}} is not available in Ignite.NET.

It looks like the requirement is to add an injectable {{ComputeTaskSession}} in 
Ignite.NET exposing the {{SetAttributes}} operation similar to what the 
{{ComputeTaskSession}} does in Java.

h4. Reproducer

We expect more or less ordered output from the below reproducer. The output may 
not be completely ordered since completely ordered output requires all the jobs 
to land on the server node in single batch and this reproducer cannot guarantee 
that:
{noformat}
>>> Completed job with priority 0
>>> Completed job with priority 9
>>> Completed job with priority 8
>>> Completed job with priority 7
>>> Completed job with priority 6
>>> Completed job with priority 5
>>> Completed job with priority 4
>>> Completed job with priority 3
>>> Completed job with priority 2
>>> Completed job with priority 1
{noformat}

{{PriorityQueueCollisionSpiTest.cs}}:
{code:java}
public class PriorityQueueCollisionSpiTest
{
    private static ITestOutputHelper? _output;
    /// <summary>
    /// Schedules jobs according to <see 
cref="IComputeTask{TArg,TJobRes,TRes}"/>'s priority. 
    /// </summary>
    [Fact]
    public void SchedulesJobsAccordingToTaskPriority()
    {
        // Given an Ignite cluster consisting of server and client nodes
        using var ignored = Ignition.Start(GetIgniteConfiguration("server1"));
        var igniteConfiguration = GetIgniteConfiguration("app1");
        igniteConfiguration.ClientMode = true;
        using var ignite = Ignition.Start(igniteConfiguration);
        var igniteCompute = ignite.GetCompute();
        
        // And the user asynchronously executes multiple tasks, each task 
starting a job having increasing priority
        const int jobCount = 10;
        ICollection<Task> futureResultCollection = new List<Task>(jobCount);
        for (var priority = 0; priority < jobCount; priority++)
        {
            var task = new PriorityTask(priority);
            var futureResult = igniteCompute.ExecuteAsync(task, jobCount);
            futureResultCollection.Add(futureResult);
        }

        // When all the jobs complete
        Task.WaitAll(futureResultCollection.ToArray());
        
        // Then the ">>> Completed job with priority" console output 
demonstrates that the jobs completed in the
        // decreasing priority order, more or less.
    }

    private static IgniteConfiguration GetIgniteConfiguration(string 
igniteName) =>
        new()
        {
            ConsistentId = igniteName,
            IgniteInstanceName = igniteName,
            SpringConfigUrl = "ignite-sandbox.xml",
            DiscoverySpi = new TcpDiscoverySpi
            {
                IpFinder = new TcpDiscoveryStaticIpFinder {Endpoints = new 
List<string> {"127.0.0.1:48700"}},
                LocalPort = 48700
            },
            FailureDetectionTimeout = TimeSpan.FromMinutes(10),
            ClientFailureDetectionTimeout = TimeSpan.FromMinutes(10),
            JvmOptions = new List<string> 
{"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"}
        };

    /// <summary>
    /// <see cref="IComputeTask{TArg,TJobRes,TRes}"/> implementation that 
single <see cref="IComputeJob{TRes}"/>s with
    /// the specified priority.
    /// </summary>
    [ComputeTaskSessionFullSupport]
    private sealed class PriorityTask : ComputeTaskSplitAdapter<int, bool, bool>
    {
        private readonly int _priority;
        [TaskSessionResource] private IComputeTaskSession _taskSession;
        [InstanceResource] private IIgnite _ignite;

        public PriorityTask(int priority)
        {
            _priority = priority;
        }

        /// <inheritdoc />
        public override bool Reduce(IList<IComputeJobResult<bool>> results) => 
results.All(r => r.Data);

        /// <inheritdoc />
        protected override ICollection<IComputeJob<bool>> Split(int gridSize, 
int jobCount)
        {
            IComputeJob<bool> job = new PriorityJob(_priority);
            _taskSession.SetAttribute("grid.task.priority", _priority);
            var actual = _taskSession.GetAttribute<int>("grid.task.priority");
            Assert.Equal(_priority, actual);
            return new List<IComputeJob<bool>> {job};
        }
    }

    /// <summary>
    /// <see cref="IComputeJob{TRes}"/> implementation with a priority 
indicator.
    /// </summary>
    private class PriorityJob : ComputeJobAdapter<bool>
    {
        private readonly int _priority;
        [TaskSessionResource] private IComputeTaskSession _taskSession;
        [InstanceResource] private IIgnite _ignite;

        public PriorityJob(int priority)
        {
            _priority = priority;
        }

        /// <inheritdoc />
        public override bool Execute()
        {
            _output?.WriteLine($">>> Completed job with priority {_priority}");
            return true;
        }
    }
}
{code}

{{ignite-sandbox.xml}}:
{code:xml}
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans";
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
       xmlns:util="http://www.springframework.org/schema/util";
       xmlns:context="http://www.springframework.org/schema/context";
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-2.5.xsd";
>
    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="collisionSpi">
            <bean 
class="org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi">
                <property name="parallelJobsNumber" value="1"/>
                <property name="starvationPreventionEnabled" value="false"/>
            </bean>
        </property>
    </bean>
</beans>
{code}

  was:
We want Apache Ignite to support [priority 
ordering|https://ignite.apache.org/docs/latest/distributed-computing/job-scheduling#priority-ordering]
 of Ignite.NET compute jobs on the same node.

h4. Analysis

{{PriorityQueueCollisionSpi}} does priority ordering. The problem is the 
{{PriorityQueueCollisionSpi}} expects the user to provide job priorities 
via the {{ComputeTaskSession}}'s "{{grid.task.priority}}" attribute and the 
{{ComputeTaskSession}} is not available in Ignite.NET.

It looks like the requirement is to add an injectable {{ComputeTaskSession}} in 
Ignite.NET exposing the {{SetAttributes}} operation similar to what the 
{{ComputeTaskSession}} does in Java.

h4. Reproducer

We expect more or less ordered output from the below reproducer. The output may 
not be completely ordered since this reproducer does not guarantee :
{noformat}
>>> Completed job with priority 0
>>> Completed job with priority 9
>>> Completed job with priority 8
>>> Completed job with priority 7
>>> Completed job with priority 6
>>> Completed job with priority 5
>>> Completed job with priority 4
>>> Completed job with priority 3
>>> Completed job with priority 2
>>> Completed job with priority 1
{noformat}

{{PriorityQueueCollisionSpiTest.cs}}:
{code:java}
public class PriorityQueueCollisionSpiTest
{
    private static ITestOutputHelper? _output;
    /// <summary>
    /// Schedules jobs according to <see 
cref="IComputeTask{TArg,TJobRes,TRes}"/>'s priority. 
    /// </summary>
    [Fact]
    public void SchedulesJobsAccordingToTaskPriority()
    {
        // Given an Ignite cluster consisting of server and client nodes
        using var ignored = Ignition.Start(GetIgniteConfiguration("server1"));
        var igniteConfiguration = GetIgniteConfiguration("app1");
        igniteConfiguration.ClientMode = true;
        using var ignite = Ignition.Start(igniteConfiguration);
        var igniteCompute = ignite.GetCompute();
        
        // And the user asynchronously executes multiple tasks, each task 
starting a job having increasing priority
        const int jobCount = 10;
        ICollection<Task> futureResultCollection = new List<Task>(jobCount);
        for (var priority = 0; priority < jobCount; priority++)
        {
            var task = new PriorityTask(priority);
            var futureResult = igniteCompute.ExecuteAsync(task, jobCount);
            futureResultCollection.Add(futureResult);
        }

        // When all the jobs complete
        Task.WaitAll(futureResultCollection.ToArray());
        
        // Then the ">>> Completed job with priority" console output 
demonstrates that the jobs completed in the
        // decreasing priority order, more or less.
    }

    private static IgniteConfiguration GetIgniteConfiguration(string 
igniteName) =>
        new()
        {
            ConsistentId = igniteName,
            IgniteInstanceName = igniteName,
            SpringConfigUrl = "ignite-sandbox.xml",
            DiscoverySpi = new TcpDiscoverySpi
            {
                IpFinder = new TcpDiscoveryStaticIpFinder {Endpoints = new 
List<string> {"127.0.0.1:48700"}},
                LocalPort = 48700
            },
            FailureDetectionTimeout = TimeSpan.FromMinutes(10),
            ClientFailureDetectionTimeout = TimeSpan.FromMinutes(10),
            JvmOptions = new List<string> 
{"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"}
        };

    /// <summary>
    /// <see cref="IComputeTask{TArg,TJobRes,TRes}"/> implementation that 
single <see cref="IComputeJob{TRes}"/>s with
    /// the specified priority.
    /// </summary>
    [ComputeTaskSessionFullSupport]
    private sealed class PriorityTask : ComputeTaskSplitAdapter<int, bool, bool>
    {
        private readonly int _priority;
        [TaskSessionResource] private IComputeTaskSession _taskSession;
        [InstanceResource] private IIgnite _ignite;

        public PriorityTask(int priority)
        {
            _priority = priority;
        }

        /// <inheritdoc />
        public override bool Reduce(IList<IComputeJobResult<bool>> results) => 
results.All(r => r.Data);

        /// <inheritdoc />
        protected override ICollection<IComputeJob<bool>> Split(int gridSize, 
int jobCount)
        {
            IComputeJob<bool> job = new PriorityJob(_priority);
            _taskSession.SetAttribute("grid.task.priority", _priority);
            var actual = _taskSession.GetAttribute<int>("grid.task.priority");
            Assert.Equal(_priority, actual);
            return new List<IComputeJob<bool>> {job};
        }
    }

    /// <summary>
    /// <see cref="IComputeJob{TRes}"/> implementation with a priority 
indicator.
    /// </summary>
    private class PriorityJob : ComputeJobAdapter<bool>
    {
        private readonly int _priority;
        [TaskSessionResource] private IComputeTaskSession _taskSession;
        [InstanceResource] private IIgnite _ignite;

        public PriorityJob(int priority)
        {
            _priority = priority;
        }

        /// <inheritdoc />
        public override bool Execute()
        {
            _output?.WriteLine($">>> Completed job with priority {_priority}");
            return true;
        }
    }
}
{code}

{{ignite-sandbox.xml}}:
{code:xml}
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans";
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
       xmlns:util="http://www.springframework.org/schema/util";
       xmlns:context="http://www.springframework.org/schema/context";
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-2.5.xsd";
>
    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="collisionSpi">
            <bean 
class="org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi">
                <property name="parallelJobsNumber" value="1"/>
                <property name="starvationPreventionEnabled" value="false"/>
            </bean>
        </property>
    </bean>
</beans>
{code}


> Ignite.NET support for priority ordering of Compute jobs
> --------------------------------------------------------
>
>                 Key: IGNITE-22349
>                 URL: https://issues.apache.org/jira/browse/IGNITE-22349
>             Project: Ignite
>          Issue Type: Improvement
>          Components: .NET, compute, platforms
>    Affects Versions: 2.16
>            Reporter: Alexey Kukushkin
>            Assignee: Alexey Kukushkin
>            Priority: Major
>              Labels: .net, compute, platforms
>
> We want Apache Ignite to support [priority 
> ordering|https://ignite.apache.org/docs/latest/distributed-computing/job-scheduling#priority-ordering]
>  of Ignite.NET compute jobs on the same node.
> h4. Analysis
> {{PriorityQueueCollisionSpi}} does priority ordering. The problem is the 
> {{PriorityQueueCollisionSpi}} expects the user to provide job priorities 
> via the {{ComputeTaskSession}}'s "{{grid.task.priority}}" attribute and the 
> {{ComputeTaskSession}} is not available in Ignite.NET.
> It looks like the requirement is to add an injectable {{ComputeTaskSession}} 
> in Ignite.NET exposing the {{SetAttributes}} operation similar to what the 
> {{ComputeTaskSession}} does in Java.
> h4. Reproducer
> We expect more or less ordered output from the below reproducer. The output 
> may not be completely ordered since completely ordered output requires all 
> the jobs to land on the server node in single batch and this reproducer 
> cannot guarantee that:
> {noformat}
> >>> Completed job with priority 0
> >>> Completed job with priority 9
> >>> Completed job with priority 8
> >>> Completed job with priority 7
> >>> Completed job with priority 6
> >>> Completed job with priority 5
> >>> Completed job with priority 4
> >>> Completed job with priority 3
> >>> Completed job with priority 2
> >>> Completed job with priority 1
> {noformat}
> {{PriorityQueueCollisionSpiTest.cs}}:
> {code:java}
> public class PriorityQueueCollisionSpiTest
> {
>     private static ITestOutputHelper? _output;
>     /// <summary>
>     /// Schedules jobs according to <see 
> cref="IComputeTask{TArg,TJobRes,TRes}"/>'s priority. 
>     /// </summary>
>     [Fact]
>     public void SchedulesJobsAccordingToTaskPriority()
>     {
>         // Given an Ignite cluster consisting of server and client nodes
>         using var ignored = Ignition.Start(GetIgniteConfiguration("server1"));
>         var igniteConfiguration = GetIgniteConfiguration("app1");
>         igniteConfiguration.ClientMode = true;
>         using var ignite = Ignition.Start(igniteConfiguration);
>         var igniteCompute = ignite.GetCompute();
>         
>         // And the user asynchronously executes multiple tasks, each task 
> starting a job having increasing priority
>         const int jobCount = 10;
>         ICollection<Task> futureResultCollection = new List<Task>(jobCount);
>         for (var priority = 0; priority < jobCount; priority++)
>         {
>             var task = new PriorityTask(priority);
>             var futureResult = igniteCompute.ExecuteAsync(task, jobCount);
>             futureResultCollection.Add(futureResult);
>         }
>         // When all the jobs complete
>         Task.WaitAll(futureResultCollection.ToArray());
>         
>         // Then the ">>> Completed job with priority" console output 
> demonstrates that the jobs completed in the
>         // decreasing priority order, more or less.
>     }
>     private static IgniteConfiguration GetIgniteConfiguration(string 
> igniteName) =>
>         new()
>         {
>             ConsistentId = igniteName,
>             IgniteInstanceName = igniteName,
>             SpringConfigUrl = "ignite-sandbox.xml",
>             DiscoverySpi = new TcpDiscoverySpi
>             {
>                 IpFinder = new TcpDiscoveryStaticIpFinder {Endpoints = new 
> List<string> {"127.0.0.1:48700"}},
>                 LocalPort = 48700
>             },
>             FailureDetectionTimeout = TimeSpan.FromMinutes(10),
>             ClientFailureDetectionTimeout = TimeSpan.FromMinutes(10),
>             JvmOptions = new List<string> 
> {"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"}
>         };
>     /// <summary>
>     /// <see cref="IComputeTask{TArg,TJobRes,TRes}"/> implementation that 
> single <see cref="IComputeJob{TRes}"/>s with
>     /// the specified priority.
>     /// </summary>
>     [ComputeTaskSessionFullSupport]
>     private sealed class PriorityTask : ComputeTaskSplitAdapter<int, bool, 
> bool>
>     {
>         private readonly int _priority;
>         [TaskSessionResource] private IComputeTaskSession _taskSession;
>         [InstanceResource] private IIgnite _ignite;
>         public PriorityTask(int priority)
>         {
>             _priority = priority;
>         }
>         /// <inheritdoc />
>         public override bool Reduce(IList<IComputeJobResult<bool>> results) 
> => results.All(r => r.Data);
>         /// <inheritdoc />
>         protected override ICollection<IComputeJob<bool>> Split(int gridSize, 
> int jobCount)
>         {
>             IComputeJob<bool> job = new PriorityJob(_priority);
>             _taskSession.SetAttribute("grid.task.priority", _priority);
>             var actual = _taskSession.GetAttribute<int>("grid.task.priority");
>             Assert.Equal(_priority, actual);
>             return new List<IComputeJob<bool>> {job};
>         }
>     }
>     /// <summary>
>     /// <see cref="IComputeJob{TRes}"/> implementation with a priority 
> indicator.
>     /// </summary>
>     private class PriorityJob : ComputeJobAdapter<bool>
>     {
>         private readonly int _priority;
>         [TaskSessionResource] private IComputeTaskSession _taskSession;
>         [InstanceResource] private IIgnite _ignite;
>         public PriorityJob(int priority)
>         {
>             _priority = priority;
>         }
>         /// <inheritdoc />
>         public override bool Execute()
>         {
>             _output?.WriteLine($">>> Completed job with priority 
> {_priority}");
>             return true;
>         }
>     }
> }
> {code}
> {{ignite-sandbox.xml}}:
> {code:xml}
> <?xml version="1.0" encoding="utf-8"?>
> <beans xmlns="http://www.springframework.org/schema/beans";
>        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>        xmlns:util="http://www.springframework.org/schema/util";
>        xmlns:context="http://www.springframework.org/schema/context";
>        xsi:schemaLocation="
>         http://www.springframework.org/schema/beans
>         http://www.springframework.org/schema/beans/spring-beans.xsd
>         http://www.springframework.org/schema/util
>         http://www.springframework.org/schema/util/spring-util-2.5.xsd";
> >
>     <bean class="org.apache.ignite.configuration.IgniteConfiguration">
>         <property name="collisionSpi">
>             <bean 
> class="org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi">
>                 <property name="parallelJobsNumber" value="1"/>
>                 <property name="starvationPreventionEnabled" value="false"/>
>             </bean>
>         </property>
>     </bean>
> </beans>
> {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to