Perpustakaan Dirancang untuk Create Custom Workflow, Orquestation Antara Komponen, Layanan Microservices dan Utilitas Otomasi Lainnya, Dibuat di Dotnet Versi 6
Perpustakaan ini telah dirancang untuk memiliki ekosistem entitas yang berorientasi pada orkestrasi dari segala jenis proses. Dari proses paling sederhana seperti panggilan antara beberapa kelas kami ke proses yang lebih kompleks seperti panggilan ke layanan mikro, dll. Namun, selalu, dengan cara deklaratif dan mencari untuk menyimpan kode dalam hal bersarang yang membosankan dan kompleks dari "jika", "lain" ... dll. Struktur
Dalam repositori ini, akan menjadi kelas inti dari ekosistem ini, dikelompokkan di bawah namespace magnett.automation.core. Beberapa kelas ini dapat digunakan di luar ruang lingkup menciptakan alur kerja, karena cukup umum untuk menjadi berguna secara mandiri.
Dalam namespace ini kami menemukan kelas utilitas yang digunakan di dalam kelas perpustakaan
Konteks konsep adalah sesuatu yang sangat generik dan digunakan dalam beberapa bidang. Bagi kami, konteks akan menjadi ruang umum di mana nilai disimpan untuk dibagi antara beberapa komponen, adalah bahwa mereka adalah nilai dari tipe heterogen.
Oleh karena itu, kami berada di depan sistem kunci/nilai, di mana nilainya akan dari jenis apa pun.
Struktur konteksnya sederhana, hanya dibentuk oleh kelas konteks , yang akan menjadi input dan pengambilan kelas nilai kami, dan antarmuka IContextVault yang akan menjadi definisi lemari besi tempat nilai -nilai disimpan.
Secara default, kami akan memiliki implementasi IContextVault , di mana ia akan menyimpan nilai -nilai dalam memori, tetapi akan terbuka untuk implementasi lain yang menyimpan nilai -nilai ini dengan cara lain.
Kami akan menggunakan Class Contextfield untuk mendapatkan dan menetapkan nilai dalam konteks, dengan kelas ini kami dapat menentukan jenis dan nama kelas.
Contoh cara mendapatkan / mengatur nilai dalam konteks
var context = Context . Create ( ) ;
var field = ContextField < int > . Create ( "FieldName" ) ;
//Set Value
context . Store ( field , random . Next ( 1000 ) ) ;
//Get Value
var value = context . Value ( field ) ; Kami memiliki beberapa antarmuka untuk definisi mesin negara serta eksekusi. Definisi mesin akan dipisahkan dari pelaksanaan mesin itu sendiri, untuk menghindari kopling dan pemisahan tanggung jawab yang jelas.
Antarmuka utama adalah imachine . Dengan antarmuka ini kita akan memiliki akses ke keadaan saat ini, antarmuka iState , dan kemungkinan transisi ke negara lain menggunakan kode tindakan yang menghasilkan transisi, entitas ITransaction , ke negara lain.
Tidak mungkin untuk beralih dari satu negara ke negara lain secara langsung, hanya melalui transisi, sehingga kami memiliki model yang dapat kami berikan dari satu khusus.
Keadaan tanpa transisi yang ditentukan dapat diberikan dan ini berarti bahwa negara adalah terminal. Dengan cara ini, kita dapat mendefinisikan mesin yang terbatas atau tidak terbatas.
Mengenai bagian runtime, definisi mesin akan dilakukan dari antarmuka Imachinedefinition , yang akan dihasilkan dari kelas MachinedefinitionBuilder .
Contoh Kode Definisi Mesin
//Helper class with states enumeration
public class State : Enumeration
{
public static readonly State Init = new State ( 1 , nameof ( Init ) ) ;
public static readonly State Working = new State ( 2 , nameof ( Working ) ) ;
public static readonly State Paused = new State ( 3 , nameof ( Paused ) ) ;
public static readonly State Finished = new State ( 4 , nameof ( Finished ) ) ;
private State ( int id , string name ) : base ( id , name )
{
}
}
//Helper class with action enumerations
public class Action : Enumeration
{
public static readonly Action Start = new Action ( 1 , nameof ( Start ) ) ;
public static readonly Action Pause = new Action ( 2 , nameof ( Pause ) ) ;
public static readonly Action Continue = new Action ( 3 , nameof ( Continue ) ) ;
public static readonly Action Finish = new Action ( 4 , nameof ( Finish ) ) ;
private Action ( int id , string name ) : base ( id , name )
{
}
}
//Now we can create a definition
_definition = MachineDefinitionBuilder . Create ( )
. InitialState ( State . Init )
. OnAction ( Action . Start ) . ToState ( State . Working )
. Build ( )
. AddState ( State . Working )
. OnAction ( Action . Pause ) . ToState ( State . Paused )
. OnAction ( Action . Finish ) . ToState ( State . Finished )
. Build ( )
. AddState ( State . Paused )
. OnAction ( Action . Continue ) . ToState ( State . Working )
. Build ( )
. AddState ( State . Finished )
. Build ( )
. BuildDefinition ( ) ;Contoh pembuatan mesin dan kode penggunaan.
var machine = Machine
. Create ( SimpleMachineDefinition . GetDefinition ( ) ) ;
machine . Dispatch ( Action . Start ) ;
var currentState = machine . State ; Di bawah namespace ini, kami akan memiliki kelas yang diperlukan untuk menentukan alur kerja dan menjalankannya. Seperti pada bagian sebelumnya, kami akan menjaga definisi alur kerja terpisah dari eksekusi.
Pemisahan ini akan dilakukan dengan menggunakan IWorkFlowDefinition dan IWorkFlowRunner Interfaces.
Untuk merangkum definisi dan eksekusi, kami memiliki antarmuka IFLOW , antarmuka ini juga akan memungkinkan kami di masa depan untuk membangun subflow, membuat aliran yang dienkapsulasi sebagai layanan dalam aplikasi yang lebih kompleks ... dll.
Jika kita berpikir dalam aliran dasar, hanya dan simpul awal untuk mengatur ulang nilai bidang, node berikutnya hanya untuk menghilangkan angka acak, dan simpul akhir untuk menjumlahkan kedua nilai definisi harus di suatu hari seperti itu.
Contoh kode definisi alur kerja.
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 ( ) ;Sebelumnya Anda telah mendefinisikan beberapa kelas pembantu seperti ContextDefinition, ini hanya kelas untuk berisi bidang konteks dan untuk menghindari duplikasi dengan definisi nama.
internal 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 ( ) ;
}
}Kami telah membuat juga kelas abstrak yang umum yang akan kami gunakan sebagai kelas dasar untuk semua kelas simpul kami, kami akan menggunakan sebagai cara untuk memastikan bahwa semua node memiliki conxtextDefinition yang tersedia
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 ) ) ;
}
}Kami memiliki dua tipe simpul sinkronisasi dan async, di bawah antarmuka inode dan inodeasync , sehingga kami dapat menggunakan node sebagai pembungkus dari kedua jenis proses. Dalam contoh ini kita hanya memiliki implementasi sinkronisasi.
Dalam contoh kami, kami hanya akan menggunakan node sinkronisasi.
Contoh node
internal class ResetValue : Common
{
#region ExitCodes
public class ExitCode : Enumeration
{
public static readonly ExitCode Ok = new ExitCode ( 1 , "Ok" ) ;
private ExitCode ( int id , string name ) : base ( id , name )
{
}
}
#endregion
private ResetValue ( CommonNamedKey key , ContextDefinition contextDefinition ) :
base ( key , contextDefinition )
{
}
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 ) ;
}
}Kode Keluar Kelas Dalam hanyalah kelas penolong lain, dibangun di atas kelas enumerasi dengan definisi kode keluar yang tersedia untuk node ini, kami juga menggunakan somthin similira
Seorang pelari, untuk membuat instantiate sendiri, perlu menerima definisi alur kerja dan contoh konteks yang akan digunakan untuk berbagi informasi antar node. Setelah pelari dieksekusi, kami dapat mengambil nilai pengembalian dari konteks jika ada.
Kami memiliki kelas abstrak flowrunnerbase sehingga kami dapat mengimplementasikan pelari khusus kami, langkah ke langkah, didistribusikan, dll.
Contoh Flow Runner
var flowRunner = FlowRunner . Create ( definition , Context . Create ( ) ) ;
var exit = await flowRunner . Start ( ) ;Aliran kelas seperti yang kami katakan sebelumnya, ini adalah pembungkus untuk semua proses ini, sekarang memiliki fungsi dasar tetapi dalam versi mendatang akan digunakan sebagai kelas utama untuk manajemen alur kerja.
var definition = SimpleFlowDefinition . GetDefinition ( ) ;
var context = Context . Create ( ) ;
var flow = Flow . Create ( FlowRunner . Create ( definition , context ) ) ;
var exit = await flow . Run ( ) ;