Skip to content

Commit 9180d2e

Browse files
committed
Refactor queue to introduce life cycle actions
1 parent 79f1b8d commit 9180d2e

34 files changed

+414
-174
lines changed

docs-src/queuing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ This is useful for when order matters.
8787
Also, if one command in the chain fails, then subsequent commands are not run at all.
8888
This affords the opportunity to add additional code that records which command failed, then resuming the command chain where it left off.
8989

90-
Here is a an example of how to chain an imaginary file transfer command together:
90+
Here is a an example of how to chain a series of (imaginary) file transfer commands together:
9191

9292
```c#
9393
Subject.Publish(new[] {

docs-src/scheduling.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,6 @@ namespace MyCommandPlugin
4242
* Run a lambda expression every ten minutes.
4343
*/
4444
schedule.Job(() => Console.WriteLine("Hello, world!")).EveryTenMinutes();
45-
46-
/*
47-
* Run a parameterless method every five minutes.
48-
*/
49-
schedule.Job(() => Foo.Bar).EverySecond();
5045
}
5146
}
5247
}
@@ -120,6 +115,20 @@ Run a command daily at a specific time (at 10:30pm in this example):
120115
schedule.Job(new MyCommand()).DailyAt(22, 30);
121116
```
122117

118+
## Scheduling a Chain of Commands
119+
120+
A group of commands can be scheduled as an atomic batch.
121+
122+
123+
```c#
124+
schedule.Job(new[] {
125+
new MyFileTransfer(filePath1),
126+
new MyFileTransfer(filePath2),
127+
new MyFileTransfer(filePath3),
128+
});
129+
```
130+
131+
123132
## Lifecycle Events
124133

125134
Schedule commands can have lifecycle events.

src/InEngine.Commands/AlwaysFail.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public override void Run()
1717
public override void Failed(Exception exception)
1818
{
1919
Error(exception.Message);
20+
if (exception.InnerException != null)
21+
Error(exception.InnerException.Message);
2022
}
2123
}
2224
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using BeekmanLabs.UnitTesting;
4+
using InEngine.Commands;
5+
using InEngine.Core.Commands;
6+
using InEngine.Core.Queuing;
7+
using Moq;
8+
using NUnit.Framework;
9+
using Serialize.Linq.Extensions;
10+
11+
namespace InEngine.Core.Test.Queuing
12+
{
13+
[TestFixture]
14+
public class EnqueueTest : TestBase
15+
{
16+
public Mock<QueueAdapter> MockQueueAdapter { get; set; }
17+
18+
//[SetUp]
19+
//public void Setup()
20+
//{
21+
// InEngineSettings.BasePath = TestContext.CurrentContext.TestDirectory;
22+
// MockQueueClient = new Mock<IQueueClient>();
23+
// Subject.QueueClient = MockQueueClient.Object;
24+
//}
25+
26+
//[Test]
27+
//public void ShouldPublishCommand()
28+
//{
29+
// var command = new AlwaysSucceed();
30+
// MockQueueClient.Setup(x => x.Publish(command));
31+
32+
// Subject.Publish(command);
33+
34+
// MockQueueClient.Verify(x => x.Publish(command), Times.Once());
35+
//}
36+
37+
//[Test]
38+
//public void ShouldPublishLambdaCommand()
39+
//{
40+
// Expression<Action> expression = () => Console.Write("Hello, world.");
41+
// var lambda = new Lambda(expression.ToExpressionNode());
42+
// MockQueueClient.Setup(x => x.Publish(It.IsAny<Lambda>()));
43+
44+
// Subject.Publish(lambda);
45+
46+
// MockQueueClient.Verify(x => x.Publish(It.IsAny<Lambda>()), Times.Once());
47+
//}
48+
49+
//[Test]
50+
//public void ShouldPublishChainOfCommands()
51+
//{
52+
// var commands = new[] {
53+
// new AlwaysSucceed(),
54+
// new AlwaysSucceed(),
55+
// new AlwaysSucceed(),
56+
// new AlwaysSucceed(),
57+
// };
58+
// MockQueueClient.Setup(x => x.Publish(It.IsAny<Chain>()));
59+
60+
// Subject.Publish(commands);
61+
62+
// MockQueueClient.Verify(x => x.Publish(It.Is<Chain>(y => y.Commands.Equals(commands))), Times.Once());
63+
//}
64+
}
65+
}

src/InEngine.Core.Test/Queuing/QueueTest.cs renamed to src/InEngine.Core.Test/Queuing/QueueAdapterTest.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace InEngine.Core.Test.Queuing
1212
{
1313
[TestFixture]
14-
public class QueueTest : TestBase<Queue>
14+
public class QueueAdapterTest : TestBase<QueueAdapter>
1515
{
1616
public Mock<IQueueClient> MockQueueClient { get; set; }
1717

@@ -45,21 +45,5 @@ public void ShouldPublishLambdaCommand()
4545

4646
MockQueueClient.Verify(x => x.Publish(It.IsAny<Lambda>()), Times.Once());
4747
}
48-
49-
[Test]
50-
public void ShouldPublishChainOfCommands()
51-
{
52-
var commands = new[] {
53-
new AlwaysSucceed(),
54-
new AlwaysSucceed(),
55-
new AlwaysSucceed(),
56-
new AlwaysSucceed(),
57-
};
58-
MockQueueClient.Setup(x => x.Publish(It.IsAny<Chain>()));
59-
60-
Subject.Publish(commands);
61-
62-
MockQueueClient.Verify(x => x.Publish(It.Is<Chain>(y => y.Commands.Equals(commands))), Times.Once());
63-
}
6448
}
6549
}

src/InEngine.Core/AbstractCommand.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
using System.Linq;
33
using System.Threading.Tasks;
44
using InEngine.Core.IO;
5-
using InEngine.Core.Scheduling;
65
using Konsole;
76
using Quartz;
87

98
namespace InEngine.Core
109
{
11-
abstract public class AbstractCommand : ICommand, IFailed, IJob, IWrite
10+
abstract public class AbstractCommand : ICommand, IFailed, IJob, IWrite, IHasCommandLifeCycle
1211
{
13-
public ExecutionLifeCycle ExecutionLifeCycle { get; set; }
12+
public CommandLifeCycle CommandLifeCycle { get; set; }
1413
public Write Write { get; set; }
1514
public ProgressBar ProgressBar { get; internal set; }
1615
public string Name { get; set; }
@@ -24,7 +23,7 @@ protected AbstractCommand()
2423
Name = GetType().FullName;
2524
SchedulerGroup = GetType().AssemblyQualifiedName;
2625
Write = new Write();
27-
ExecutionLifeCycle = new ExecutionLifeCycle();
26+
CommandLifeCycle = new CommandLifeCycle();
2827
SecondsBeforeTimeout = 300;
2928
}
3029

@@ -62,15 +61,15 @@ public virtual void Execute(IJobExecutionContext context)
6261

6362
try
6463
{
65-
ExecutionLifeCycle.FirePreActions(this);
64+
CommandLifeCycle.FirePreActions(this);
6665
if (SecondsBeforeTimeout <= 0)
6766
Run();
6867
else {
6968
var task = Task.Run(() => Run());
7069
if (!task.Wait(TimeSpan.FromSeconds(SecondsBeforeTimeout)))
7170
throw new Exception($"Scheduled command timed out after {SecondsBeforeTimeout} second(s).");
7271
}
73-
ExecutionLifeCycle.FirePostActions(this);
72+
CommandLifeCycle.FirePostActions(this);
7473
}
7574
catch (Exception exception)
7675
{

src/InEngine.Core/Scheduling/ExecutionLifeCycle.cs renamed to src/InEngine.Core/CommandLifeCycle.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using System;
22
using InEngine.Core.Exceptions;
33

4-
namespace InEngine.Core.Scheduling
4+
namespace InEngine.Core
55
{
6-
public class ExecutionLifeCycle
6+
public class CommandLifeCycle
77
{
88
public MailSettings MailSettings { get; set; }
99
public Action<AbstractCommand> BeforeAction { get; set; }

src/InEngine.Core/Commands/Chain.cs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,10 @@ public override void Run()
1919
}
2020
catch (Exception exception)
2121
{
22+
x.Failed(exception);
2223
throw new CommandChainFailedException(x.Name, exception);
2324
}
2425
});
2526
}
26-
27-
public override void Execute(IJobExecutionContext context)
28-
{
29-
var properties = GetType().GetProperties();
30-
context.MergedJobDataMap.ToList().ForEach(x => {
31-
var property = properties.FirstOrDefault(y => y.Name == x.Key);
32-
if (property != null)
33-
property.SetValue(this, x.Value);
34-
});
35-
36-
try
37-
{
38-
ExecutionLifeCycle.FirePreActions(this);
39-
Run();
40-
ExecutionLifeCycle.FirePostActions(this);
41-
}
42-
catch (Exception exception)
43-
{
44-
Failed(exception);
45-
}
46-
}
4727
}
4828
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using InEngine.Core.Scheduling;
3+
4+
namespace InEngine.Core
5+
{
6+
public interface IHasCommandLifeCycle
7+
{
8+
CommandLifeCycle CommandLifeCycle { get; set; }
9+
}
10+
}

src/InEngine.Core/JsonExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace InEngine.Core
44
{
5-
public static class JsonExtensions
5+
static class JsonExtensions
66
{
77
public static string SerializeToJson<T>(this T message, bool compress = false) where T : class
88
{

0 commit comments

Comments
 (0)