Skip to content

Commit

Permalink
Update readme and prepare release data (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
LHPiney authored Feb 2, 2025
1 parent 1cdba6a commit 1361a22
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 279 deletions.
120 changes: 48 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# magnett automation
[![Build](https://github.com/LHPiney/magnett-automation-core/actions/workflows/build.yml/badge.svg)](https://github.com/LHPiney/magnett-automation-core/actions/workflows/build.yml)
[![Build](https://github.com/LHPiney/magnett-automation-core/actions/workflows/build-and-analyze.yml/badge.svg)](https://github.com/LHPiney/magnett-automation-core/actions/workflows/build-and-analyze.yml)
[![Build Status](https://dev.azure.com/Magnett/Magnett.Automation/_apis/build/status/magnett-automation-core?branchName=azure-pipelines)](https://dev.azure.com/Magnett/Magnett.Automation/_build/latest?definitionId=1&branchName=azure-pipelines)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=magnett_automation&metric=alert_status)](https://sonarcloud.io/dashboard?id=magnett_automation) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=magnett_automation&metric=coverage)](https://sonarcloud.io/dashboard?id=magnett_automation)
![GitHub issues](https://img.shields.io/github/issues/lhpiney/magnett-automation-core)
![Nuget](https://img.shields.io/nuget/v/Magnett.Automation.Core)
![Nuget](https://img.shields.io/nuget/dt/Magnett.Automation.Core)

![Logo](./assets/logo.svg)
![Logo](./assets/Logo.png)

Library designed for create custom workflow, orquestation between components, microservices and other automation utilities, created on dotnet version 6
Library designed for create custom workflow, orchestration between components, microservices and other automation utilities, created on dotnet version 6

## Introduction

This library has been designed to have an ecosystem of entities oriented to the orchestration of any type of process. From the simplest processes such as calls between several of our classes to more complex processes such as calls to microservices, etc. Always, however, in a declarative way and looking to save code in terms of tedious and complex nesting of “If”, “else”... etc.
This library has been designed to have an ecosystem of entities oriented to the orchestration of any type of process. From the simplest processes such as calls between several of our classes to more complex processes such as calls to microservices, etc. Always, however, declaratively and looking to save code in terms of tedious and complex nesting of “If” “else”... etc.
Structure

In this repository, will be the core classes of this ecosystem, grouped under the namespace magnett.automation.core. Some of these classes can be used outside the scope of creating a workflow, as they are generic enough to be useful independently.
In this repository, there will be the core classes of this ecosystem, grouped under the namespace magnett.automation.core. Some of these classes can be used outside the scope of creating a workflow, as they are generic enough to be useful independently.

- Common
- Context.
Expand All @@ -24,21 +24,22 @@ In this repository, will be the core classes of this ecosystem, grouped under th

## Common

In this namespace we found utilities class used inside the libray classes
In this namespace we found utilities' class used inside the library classes

- Enumeration
- CommonNamedKey
- DictionaryWrapper

## Context

The concept context is something very generic and is used in several fields. For us, a context will be a common space where values are stored to be shared between several components, being that they are values of the heterogeneous type.
The concept context is very generic and is used in several fields.
For us, a context will be a common space where values are stored to be shared between several components, being that they are values of the heterogeneous type.

We are, therefore, in front of a key/value system, where the values will be of any type.

### Structure

The structure of the context is simple, it is formed only by the *Context* class, which will be our input and retrieval of values class, and the *IContextVault* interface which will be the definition of the vault where the values are stored.
The structure of the context is straightforward, it is formed only by the *Context* class, which will be our input and retrieval of values class, and the *IContextVault* interface which will be the definition of the vault where the values are stored.

By default, we will have an implementation of the *IContextVault*, where it will store the values in memory, but will be open for any other implementation that stores these values in any other way.

Expand All @@ -63,11 +64,11 @@ We have at our disposal several interfaces for the definition of a state machine

### Structure
The main interface is *IMachine*. with this interface we will have access to the current state, *IState* interface, and the possibility of transitioning to another state using action codes that generate a transition, *ITransaction* entity, to another state.
The main interface is *IMachine*. With this interface, we will have access to the current state, *IState* interface, and the possibility of transitioning to another state using action codes that generate a transition, *ITransaction* entity, to another state.

It is not possible to go from one state to another directly, only through a transition, so that we have a model to which states we can go from one in particular.

A state without defined transitions can be given and this means that the state is terminal. In this way, we can define finite or non-finite machines.
A state without defined transitions can be given, and this means that the state is terminal. In this way, we can define finite or non-finite machines.

Regarding the runtime part, the definition of a machine will be done from the *IMachineDefinition* interface, which will be generated from the *MachineDefinitionBuilder* class.

Expand Down Expand Up @@ -138,79 +139,59 @@ var currentState = machine.State;

## Workflows

Under this namespace, we will have the necessary classes to define a workflow and execute it. As in the previous section, we will keep the workflow definition separate from the execution.
Under this namespace, we will have the necessary classes to define a workflow and execute it. As in the previous section, we will keep the workflow definition separate from the runtime.

### Structure

This separation will be done using the *IWorkflowDefinition* and *IWorkflowRunner* interfaces.

To encapsulate the definition and execution we have the *IFlow* interface, this interface also will allow us in the future to build subflows, create flows that are encapsulated as a service within more complex applications... etc.
To encapsulate the definition and execution we have the *IFlow* interface, this interface also will allow us in the future to build sub-flows, create flows that are encapsulated as a service within more complex applications... etc.

If we think in a basic flow,just and initial node to reset field values, next node just to caculate to random numbers, and a final node to sum both values the definition should be somthin like that.
If we think of a basic flow,just and initial node to reset field values, the next node just to calculate to random numbers, and a final node to sum both values, the definition should be something like that.

Example workflow definition code.

```csharp
var contextDefinition = ContextDefinition.Create();

var definition = FlowDefinitionBuilder.Create()
.WithInitialNode(ResetValue.Create(Node.Reset, contextDefinition))
.OnExitCode(ResetValue.ExitCode.Ok).GoTo(Node.SetValue)
.Build()

.WithNode(SetValue.Create(Node.SetValue, contextDefinition))
.OnExitCode(SetValue.ExitCode.Assigned).GoTo(Node.SumValue)
.Build()

.WithNode(SumValue.Create(Node.SumValue, contextDefinition)).Build()

.BuildDefinition();
.WithInitialNode<ResetValue>(NodeName.Reset)
.OnExitCode(ResetValue.ExitCode.Ok).GoTo(NodeName.SetValue)
.Build()

.WithNode<SetValue>(NodeName.SetValue)
.OnExitCode(SetValue.ExitCode.Assigned).GoTo(NodeName.SumValue)
.Build()

.WithNode<SumValue>(NodeName.SumValue)
.Build()

.BuildDefinition();
```

Previously you have defined some helper classes like *ContextDefinition* it's just a class to contains Context field and to avoid duplication with name definitions.
Previously,
you have defined some helper classes like *ContextDefinition* it's just a static class
to contain Context field and to avoid duplication and mistakes with name definitions.

```csharp
internal class ContextDefinition
internal static class ContextDefinition
{
public ContextField<int> FirstDigit { get; }
public ContextField<int> SecondDigit { get; }
public ContextField<int> Result { get; }

private ContextDefinition()
{
FirstDigit = ContextField<int>.Create("FieldOne");
SecondDigit = ContextField<int>.Create("FieldTwo");
Result = ContextField<int>.Create("FieldResult");
}

public static ContextDefinition Create()
{
return new ContextDefinition();
}
public static ContextField<int> FirstDigit => ContextField<int>.Create("FieldOne");
public static ContextField<int> SecondDigit => ContextField<int>.Create("FieldTwo");
public static ContextField<int> Result => ContextField<int>.Create("FieldResult");
}
```
We have created also the abstract class *Common* that we will use as base class for all of our node classes, we will use as a way to ensure that all nodes have avaliable ConxtextDefinition

```csharp
internal abstract class Common : Core.WorkFlows.Implementations.Node
{
protected ContextDefinition ContextDefinition { get; }

protected Common(CommonNamedKey key, ContextDefinition contextDefinition) : base(key)
{
ContextDefinition = contextDefinition
?? throw new ArgumentNullException(nameof(contextDefinition));
}
}
```
We have two node types sync and async, under the *INode* and *INodeAsync* interfaces, so we can use nodes as a wrapper of both type of process. In this example we have only the sync implementation.
We have two node types sync and async, under the *INode* and *INodeAsync* interfaces, so we can use nodes as a wrapper of both types of process.

In our example we will use only sync nodes.
The library provides a base class for each type of node, *Node* and *NodeAsync* respectively, so we can implement our custom nodes.

In this example, we have only the sync implementation.

Example Node

```csharp
internal class ResetValue : Common
internal class ResetValue : Node
{
#region ExitCodes

Expand All @@ -222,37 +203,30 @@ internal class ResetValue : Common
{
}
}

#endregion

private ResetValue(CommonNamedKey key, ContextDefinition contextDefinition) :
base(key, contextDefinition)
public ResetValue(CommonNamedKey key) : base(key)
{

}

public override NodeExit Execute(Context context)
{
context.Store(ContextDefinition.FirstDigit, 0);
context.Store(ContextDefinition.SecondDigit, 0);
context.Store(ContextDefinition.Result, 0);

return NodeExit.Create(ExitCode.Ok.Name);
}

public static ResetValue Create(CommonNamedKey name, ContextDefinition contextDefinition)
{
return new ResetValue(name, contextDefinition);
}
}
```

The inner class *ExitCodes* is just another helper class, build over Enumeration class with the definition of avaliable exit codes for this node, we use also somthin similira

A runner, to instantiate itself, will need to receive the workflow definition and a context instance that will be used to share information between nodes. Once the runner has been executed we can retrieve return values from context if there are any.
The inner class *ExitCodes* is just another helper class, build over Enumeration class with the definition of available exit codes for this node, we use something similar

We have the abstract class *FlowRunnerBase* so we can implement our custom runners, step to step, distributed, etc..
A runner, to instantiate itself, will need to receive the workflow definition and a context instance that will be used to share information between nodes. Once the runner has been executed, we can retrieve return values from context if there are any.

We have the abstract class *FlowRunnerBase* so we can implement our custom runners, step to step, distributed, etc.

Example Flow runner

Expand All @@ -262,7 +236,7 @@ var flowRunner = FlowRunner.Create(definition, Context.Create());
var exit = await flowRunner.Start();
```

The class flow as we said before, it's a wrapper for all this process, now have basic functionalities but in future versions will be used as main class for workflow management.
The class flow, as we said before, it's a wrapper for all this process, now has basic functionalities but in future versions will be used as the main class for workflow management.

```csharp
var definition = SimpleFlowDefinition.GetDefinition();
Expand All @@ -272,3 +246,5 @@ var flow = Flow.Create(FlowRunner.Create(definition, context));

var exit = await flow.Run();
```

Thanks for reading, and I hope you find this library useful. Feedback is always welcome.
10 changes: 8 additions & 2 deletions RELEASE-NOTES.MD
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
v.0.5.1
- Initial serious release

v.6.0
v.0.6.0
- Split Runtime from Definition in Workflow declaration
- Add support for net Core 8.0
- Add support for net Core 8.

v.1.0.0
- Definition of Workflow does not require an instance, just using generic type
- Total separation between Definition and Runtime
- Minor changes in runtime to increase performance
- Add support for net Core 9.0
Binary file added assets/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 0 additions & 99 deletions assets/Logo.svg

This file was deleted.

Loading

0 comments on commit 1361a22

Please sign in to comment.