Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dotnet-sdk): handle business exception and technical errors in task worker #1163

Merged
merged 5 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ dist/

# dotnet
global.json
*DotSettings.user
*DotSettings.user
!sdk-dotnet/Littlehorse.sln
*.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\LittleHorse.Sdk\LittleHorse.Sdk.csproj" />
</ItemGroup>

</Project>
70 changes: 70 additions & 0 deletions sdk-dotnet/Examples/ExceptionsHandlerExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using ExceptionsHandler;
using LittleHorse.Sdk;
using LittleHorse.Sdk.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace ExceptionsHandlerExample;

public abstract class Program
{
private static ServiceProvider? _serviceProvider;

private static void SetupApplication()
{
_serviceProvider = new ServiceCollection()
.AddLogging(config =>
{
config.AddConsole();
config.SetMinimumLevel(LogLevel.Debug);
})
.BuildServiceProvider();
}

private static LHConfig GetLHConfig(string[] args, ILoggerFactory loggerFactory)
{
var config = new LHConfig(loggerFactory);

string filePath = Path.Combine(Directory.GetCurrentDirectory(), ".config/littlehorse.config");
if (File.Exists(filePath))
config = new LHConfig(filePath, loggerFactory);

return config;
}

private static List<LHTaskWorker<MyWorker>> GetTaskWorkers(LHConfig config)
{
MyWorker executableExceptionHandling = new MyWorker();
var workers = new List<LHTaskWorker<MyWorker>>
{
new(executableExceptionHandling, "fail", config),
new(executableExceptionHandling, "fail-new-process", config),
new(executableExceptionHandling, "technical-failure", config),
new(executableExceptionHandling, "my-task", config)
};

return workers;
}

static void Main(string[] args)
{
SetupApplication();
if (_serviceProvider != null)
{
var loggerFactory = _serviceProvider.GetRequiredService<ILoggerFactory>();
var config = GetLHConfig(args, loggerFactory);
var workers = GetTaskWorkers(config);
foreach (var worker in workers)
{
worker.RegisterTaskDef();
}

Thread.Sleep(300);

foreach (var worker in workers)
{
worker.Start();
}
}
}
}
31 changes: 31 additions & 0 deletions sdk-dotnet/Examples/ExceptionsHandlerExample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Running Exceptions Handler Example

This is a simple demonstration of a workflow that handles the failure of a task with
the handleException() functionality, which spawns a child thread and then
resumes execution when the handler thread completes.

Let's run the example in `ExceptionsHandlerExample`

```
dotnet build
dotnet run
```

In another terminal, use `lhctl` to run the workflow:

```
lhctl run example-exception-handler
```

In addition, you can check the result with:

```
# This call shows the result
lhctl get wfRun <wf_run_id>

# This will show you all nodes in tha run
lhctl list nodeRun <wf_run_id>

# This shows the task run information
lhctl get taskRun <wf_run_id> <task_run_global_id>
```
56 changes: 56 additions & 0 deletions sdk-dotnet/Examples/ExceptionsHandlerExample/Worker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using LittleHorse.Common.Proto;
using LittleHorse.Sdk.Worker;
using LHTaskException = LittleHorse.Sdk.Exceptions.LHTaskException;

namespace ExceptionsHandler
{
public class MyWorker
{
[LHTaskMethod("fail")]
public void Fail()
{
Random random = new Random();
int randomNumber = random.Next(6, 10);
var message = $"Throw New Failing Task {randomNumber}.";
if (randomNumber > 5)
{
throw new LHTaskException("Fail", message);
}

Console.WriteLine(message);
}

[LHTaskMethod("fail-new-process")]
public void FailNewProcess()
{
Random random = new Random();
int randomNumber = random.Next(1, 10);
var message = $"Throw Other Failing Task {randomNumber}";
if (randomNumber < 8)
{
VariableValue content = new VariableValue
{
Str = "This is a problem"
};
throw new LHTaskException("Fail-New-Task", message, content);
}

Console.WriteLine(message);
}

[LHTaskMethod("technical-failure")]
public void FailForTechnicalReason()
{
String message = null!;
int result = message.Length;
Console.WriteLine(result);
}

[LHTaskMethod("my-task")]
public string PassingTask()
{
Console.WriteLine("Executing passing task.");
return "woohoo!";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
45 changes: 27 additions & 18 deletions sdk-dotnet/Examples/MaskedFieldsExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Examples.BasicExample;
using LittleHorse.Sdk;
using LittleHorse.Sdk.Worker;

public class Program
namespace MaskedFieldsExample;

public abstract class Program
{
private static ServiceProvider? _serviceProvider;
private static void SetupApplication()
Expand All @@ -26,6 +27,19 @@ private static LHConfig GetLHConfig(string[] args, ILoggerFactory loggerFactory)

return config;
}

private static List<LHTaskWorker<MyWorker>> GetTaskWorkers(LHConfig config)
{
MyWorker executableExceptionHandling = new MyWorker();
var workers = new List<LHTaskWorker<MyWorker>>
{
new(executableExceptionHandling, "create-greet", config),
new(executableExceptionHandling, "update-greet", config),
new(executableExceptionHandling, "delete-greet", config)
};

return workers;
}

static void Main(string[] args)
{
Expand All @@ -34,23 +48,18 @@ static void Main(string[] args)
{
var loggerFactory = _serviceProvider.GetRequiredService<ILoggerFactory>();
var config = GetLHConfig(args, loggerFactory);
var workers = GetTaskWorkers(config);
foreach (var worker in workers)
{
worker.RegisterTaskDef();
}

MyWorker executableCreateGreet = new MyWorker();
var taskWorkerCreate = new LHTaskWorker<MyWorker>(executableCreateGreet, "create-greet", config);
MyWorker executableUpdateGreet = new MyWorker();
var taskWorkerUpdate = new LHTaskWorker<MyWorker>(executableUpdateGreet, "update-greet", config);
MyWorker executableDeleteGreet = new MyWorker();
var taskWorkerDelete = new LHTaskWorker<MyWorker>(executableDeleteGreet, "delete-greet", config);

taskWorkerCreate.RegisterTaskDef();
taskWorkerUpdate.RegisterTaskDef();
taskWorkerDelete.RegisterTaskDef();
Thread.Sleep(300);

Thread.Sleep(1000);

taskWorkerCreate.Start();
taskWorkerUpdate.Start();
taskWorkerDelete.Start();
foreach (var worker in workers)
{
worker.Start();
}
}
}
}
}
2 changes: 1 addition & 1 deletion sdk-dotnet/Examples/MaskedFieldsExample/Worker.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using LittleHorse.Sdk.Worker;

namespace Examples.BasicExample
namespace MaskedFieldsExample
{
public class MyWorker
{
Expand Down
17 changes: 13 additions & 4 deletions sdk-dotnet/LittleHorse.Sdk.Tests/Helper/LHMappingHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ public void LHHelper_WithSystemBytesVariableType_ShouldReturnLHVariableBytesType
Assert.True(result == VariableType.Bytes);
}

[Fact]
public void LHHelper_WithSystemVoidVariableType_ShouldReturnLHVariableJsonObjType()
{
var type = typeof(void);

var result = LHMappingHelper.MapDotNetTypeToLHVariableType(type);

Assert.True(result == VariableType.JsonObj);
}

[Fact]
public void LHHelper_WithSystemArrayObjectVariableType_ShouldReturnLHVariableJsonArrType()
{
Expand Down Expand Up @@ -145,12 +155,11 @@ public void LHHelper_WithVariableValue_ShouldReturnSameValue()
}

[Fact]
public void LHHelper_WithNullLHVariableValue_ShouldThrowException()
public void LHHelper_WithNullLHVariableValue_ShouldReturnNewLHVariableValue()
{
var exception = Assert.Throws<LHInputVarSubstitutionException>
(() => LHMappingHelper.MapObjectToVariableValue(null));
var result = LHMappingHelper.MapObjectToVariableValue(null);

Assert.Equal($"There is no object to be mapped.", exception.Message);
Assert.NotNull(result);
}

[Fact]
Expand Down
22 changes: 22 additions & 0 deletions sdk-dotnet/LittleHorse.Sdk/Exceptions/LHTaskException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using LittleHorse.Common.Proto;

namespace LittleHorse.Sdk.Exceptions;

public class LHTaskException: Exception
{
public string Name { get; }

public VariableValue Content { get; }

public LHTaskException(String name, String message): base(message)
{
Name = name;
Content = new VariableValue();
}

public LHTaskException(String name, String message, VariableValue content): base(message)
{
Name = name;
Content = content;
}
}
Loading