
Halo semuanya!
Kami memutuskan untuk mendukung tema migrasi proyek menggunakan Windows Workflow Foundation ke .Net Core , yang dimulai oleh rekan-rekan dari DIRECTUM, karena kami menghadapi masalah serupa beberapa tahun yang lalu dan berjalan dengan cara kami sendiri.
Mari kita mulai dengan ceritanya
Produk unggulan kami, Avanpost IDM, adalah siklus hidup akun dan sistem manajemen akses karyawan. Dia tahu cara mengelola akses baik secara otomatis berdasarkan model peran, dan sesuai permintaan. Pada awal pembentukan produk, kami memiliki sistem swalayan yang cukup sederhana dengan alur kerja langkah demi langkah yang sederhana, yang pada prinsipnya mesin tidak diperlukan.

Namun, ketika berhadapan dengan klien besar, kami menyadari bahwa alat yang jauh lebih fleksibel diperlukan, karena persyaratan mereka untuk proses koordinasi hak akses mencari aturan alur kerja yang baik. Setelah menganalisis persyaratan, kami memutuskan untuk mengembangkan editor proses kami sendiri dalam format BPMN, sesuai untuk kebutuhan kami. Kami akan berbicara tentang pengembangan editor menggunakan React.js + SVG sedikit kemudian, dan hari ini kita akan membahas topik backend - mesin alur kerja atau mesin proses bisnis.
Persyaratan
Pada awal pengembangan sistem, kami memiliki persyaratan berikut untuk mesin:
- Dukungan untuk diagram proses, format yang dapat dimengerti, kemampuan untuk menyiarkan dari format kami ke format mesin
- Penyimpanan status proses
- Mendukung Proses Pembuatan Versi
- Dukungan untuk eksekusi paralel (cabang) dari proses
- Lisensi yang sesuai untuk menggunakan solusi dalam produk komersial yang direplikasi
- Dukungan untuk penskalaan horizontal
Setelah menganalisis pasar (untuk 2014), kami menetapkan solusi yang hampir tidak alternatif untuk .Net: Windows Workflow Foundation.
Windows Workflow Foundation (WWF)
WWF adalah teknologi Microsoft untuk mendefinisikan, mengeksekusi, dan mengelola alur kerja.
Dasar dari logikanya adalah seperangkat wadah untuk tindakan (kegiatan) dan kemampuan untuk membangun proses berurutan dari wadah ini. Wadah mungkin biasa - langkah tertentu dalam proses di mana aktivitas dilakukan. Ini bisa menjadi manajer - berisi logika percabangan.
Anda dapat menggambar proses secara langsung di Visual Studio. Diagram proses bisnis yang dikompilasi disimpan dalam Haml, yang sangat nyaman - formatnya dijelaskan, adalah mungkin untuk membuat perancang proses yang ditulis sendiri. Ini di satu sisi. Di sisi lain, Xaml bukan format yang paling nyaman untuk menyimpan deskripsi - skema yang dikompilasi untuk proses nyata lebih atau kurang ternyata sangat besar, paling tidak karena redundansi. Sangat sulit untuk dipahami, tetapi Anda harus memahaminya.
Tetapi jika, cepat atau lambat, seseorang dapat memahami zen dengan skema dan belajar membacanya, maka kurangnya transparansi dalam pengoperasian mesin itu sendiri menambah kerumitan saat pengguna menggunakan sistem. Ketika kesalahan berasal dari usus Wf, tidak selalu mungkin untuk mengetahui 100% apa sebenarnya alasan kegagalan tersebut. Sumber tertutup dan monstrositas relatif tidak membantu kasus ini. Seringkali perbaikan bug disebabkan oleh gejala.
Dalam keadilan, perlu diperjelas di sini bahwa masalah yang dijelaskan di atas, sebagian besar, telah mengganggu kami karena kustomisasi yang kuat atas Wf. Salah satu pembaca akan mengatakan dengan pasti bahwa kita sendiri menciptakan banyak masalah, dan kemudian menyelesaikannya dengan heroik. Itu perlu untuk membuat mesin buatan sendiri sejak awal. Secara umum, mereka akan benar.
Pada intinya, solusinya bekerja cukup stabil dan berhasil masuk ke produksi. Tetapi transisi dari produk kami ke .Net Core memaksa kami untuk meninggalkan WWF dan mencari mesin proses bisnis lainnya, karena Pada Mei 2019, Windows Workflow Foundation belum dimigrasi ke .Net Core. Saat kami sedang mencari mesin baru - topik dari artikel yang terpisah, tetapi pada akhirnya kami memilih Workflow Core.
Inti alur kerja
Workflow Core adalah mesin proses bisnis gratis. Ini dikembangkan di bawah lisensi MIT, yaitu dapat digunakan dengan aman dalam pengembangan komersial.
Ini dilakukan secara aktif oleh satu orang, beberapa orang lagi secara berkala melakukan permintaan penarikan. Ada port untuk bahasa lain (Java, Python, dan beberapa lainnya).
Mesin diposisikan sebagai ringan. Faktanya, ini hanya sebuah host untuk eksekusi tindakan berurutan yang dikelompokkan berdasarkan aturan bisnis apa pun.
Proyek ini memiliki dokumentasi wiki . Sayangnya, itu tidak menggambarkan semua fitur mesin. Namun, akan kurang bijaksana untuk memerlukan dokumentasi lengkap - proyek opensource didukung oleh satu penggemar. Oleh karena itu, Wiki akan cukup untuk memulai.
Di luar kotak ada dukungan untuk menyimpan status proses dalam penyimpanan eksternal (penyimpanan persistensi). Penyedia adalah standar untuk:
- Mongodb
- SQL Server
- PostgreSQL
- Sqlite
- Amazon DynamoDB
Tulis penyedia Anda tidak masalah. Kami mengambil sumber dari standar apa pun dan melakukan sebagai contoh.
Penskalaan horizontal didukung, yaitu, Anda dapat menjalankan mesin pada beberapa node sekaligus, sekaligus memiliki satu titik penyimpanan status proses (satu penyimpanan persistensi). Dalam hal ini, penempatan antrian tugas internal mesin harus dalam penyimpanan umum (rabbitMQ, sebagai opsi). Untuk mengecualikan pelaksanaan satu tugas oleh beberapa node, manajer kunci disediakan pada saat yang sama. Dengan analogi dengan penyedia penyimpanan eksternal, ada implementasi standar:
- Sewa penyimpanan Azure
- Redis
- AWS DynamoDB
- SQLServer (di sumbernya ada, tapi tidak ada yang dikatakan dalam dokumentasi)
Mengenal sesuatu yang baru adalah yang paling mudah untuk memulai dengan sebuah contoh. Jadi mari kita lakukan. Saya akan menjelaskan konstruksi proses sederhana dari awal, bersama dengan penjelasannya. Sebuah contoh mungkin tampak sangat sederhana. Saya setuju - itu sederhana. Yang paling awal.
Ayo pergi.
Langkah
Langkah adalah langkah dalam proses di mana tindakan dilakukan. Seluruh proses dibangun dari urutan langkah-langkah. Satu langkah dapat melakukan banyak tindakan, dapat diulangi, misalnya untuk beberapa acara dari luar. Ada serangkaian langkah yang diberkahi dengan logika "di luar kotak":
- Menunggu
- Jika
- Sementara
- Foreach
- Tunda
- Paralel
- Jadwalkan
- Berulang
Tentu saja, pada beberapa primitif bawaan Anda tidak tahan proses. Kami membutuhkan langkah-langkah yang menyelesaikan tugas bisnis. Karena itu, untuk saat ini, kesampingkan mereka dan ambil langkah dengan logika kita sendiri. Untuk melakukan ini, Anda harus mewarisi dari abstraksi StepBody .
public abstract class StepBody : IStepBody { public abstract ExecutionResult Run(IStepExecutionContext context); }
Metode Run dijalankan ketika proses memasuki langkah. Adalah perlu untuk menempatkan logika yang diperlukan ke dalamnya.
public abstract class StepBody : IStepBody { public abstract ExecutionResult Run(IStepExecutionContext context); }
Langkah-langkah ini mendukung injeksi ketergantungan. Untuk melakukan ini, cukup mendaftarkannya dalam wadah yang sama dengan dependensi yang diperlukan.
Jelas, proses membutuhkan konteksnya sendiri - tempat di mana hasil antara eksekusi dapat ditambahkan. Inti Wf memiliki konteksnya sendiri untuk pelaksanaan suatu proses yang menyimpan informasi tentang keadaan saat ini. Anda dapat mengaksesnya menggunakan variabel konteks dari metode Run (). Selain built-in, kita dapat menggunakan konteks kita.
Kami akan menganalisis cara menggambarkan dan mendaftarkan proses secara lebih rinci di bawah ini, untuk saat ini, kami hanya mendefinisikan kelas tertentu - konteksnya.
public class ProcessContext { public int Number1 {get;set;} public int Number2 {get;set;} public string StepResult {get;set;} public ProcessContext() { Number1 = 1; Number2 = 2; } }
Dalam Number variabel kita menulis angka; ke dalam variabel StepResult - hasil dari langkah tersebut.
Kami memutuskan konteksnya. Anda dapat menulis langkah Anda sendiri:
public class CustomStep : StepBody { private readonly Ilogger _log; public int Input1 { get; set; } public int Input2 { get; set; } public string Action { get; set; } public string Result { get; set; } public CustomStep(Ilogger log) { _log = log; } public override ExecutionResult Run(IStepExecutionContext context) { Result = βnoneβ; if (Action ==βsumβ) { Result = Number1 + Number2; } if (Action ==βdifβ){ Result = Number1 - Number2; } return ExecutionResult.Next(); } }
Logikanya sangat sederhana: dua angka dan nama operasi sampai pada input. Hasil operasi ditulis ke Hasil variabel output. Jika operasi tidak ditentukan, hasilnya tidak akan ada .
Kami memutuskan pada konteksnya, ada langkah dengan logika yang kami butuhkan juga. Sekarang kita perlu mendaftarkan proses kita di mesin.
Deskripsi proses. Registrasi di mesin.
Ada dua cara untuk menggambarkan suatu proses. Yang pertama adalah deskripsi dalam kode - hardcode.
Prosesnya dijelaskan melalui antarmuka yang lancar . Hal ini diperlukan untuk mewarisi dari antarmuka IWorkflow <T> yang digeneralisasi, di mana T adalah kelas konteks model. Dalam kasus kami, ini adalah ProcessContext .
Ini terlihat seperti ini:
public class SimpleWorkflow : IWorkflow<ProcessContext> { public void Build(IWorkflowBuilder<ProcessContext> builder) {
Deskripsi itu sendiri akan berada di dalam metode Build . Kolom Id dan Versi juga diperlukan. Jika inti mendukung proses versi - Anda dapat mendaftarkan dan versi proses dengan pengidentifikasi yang sama. Ini nyaman ketika Anda perlu memperbarui proses yang ada dan pada saat yang sama memberikan "hidup" untuk tugas yang ada.
Kami menggambarkan proses sederhana:
public class SimpleWorkflow : IWorkflow<ProcessContext> { public void Build(IWorkflowBuilder<ProcessContext> builder) { builder.StartWith<CustomStep>() .Input(step => step.Input1, data => data.Number1) .Input(step => step.Input2, data => data.Number2) .Input(step => step.Action, data => βsumβ) .Output(data => data.StepResult, step => step.Result) .EndWorkflow(); } public string Id => "SomeWorkflow"; public int Version => 1; }
Jika diterjemahkan ke bahasa "manusia", itu akan berubah menjadi seperti ini: proses dimulai dengan langkah CustomStep . Nilai bidang pitch Input1 diambil dari bidang konteks Number1 , Nilai bidang lapangan Input2 diambil dari bidang konteks Number2 , bidang tindakan secara kaku ditunjukkan dengan nilai "jumlah" . Output dari bidang Hasil ditulis ke bidang konteks StepResult . Selesaikan prosesnya.
Setuju, kode itu ternyata sangat mudah dibaca, sangat mungkin untuk mengetahuinya bahkan tanpa pengetahuan khusus dalam C #.
Tambahkan satu langkah lagi ke proses kami, yang akan menampilkan hasil dari langkah sebelumnya ke log:
public class CustomStep : StepBody { private readonly Ilogger _log; public string TextToOutput { get; set; } public CustomStep(Ilogger log) {
Dan perbarui proses:
public class SimpleWorkflow : IWorkflow<ProcessContext> { public void Build(IWorkflowBuilder<ProcessContext> builder) { builder.StartWith<CustomStep>() .Input(step => step.Input1, data => data.Number1) .Input(step => step.Input2, data => data.Number2) .Input(step => step.Action, data => βsumβ) .Output(data => data.StepResult, step => step.Result) .Then<OutputStep>.Input(step => step.TextToOutput, data => data.StepResult) .EndWorkflow(); } public string Id => "SomeWorkflow"; public int Version => 2; }
Sekarang, setelah langkah dengan operasi penjumlahan, langkah mengeluarkan hasil ke log berikut. Untuk input, kami meneruskan variabel Hasil dan konteks ke mana hasil eksekusi ditulis pada langkah terakhir. Saya akan mengambil kebebasan menyatakan bahwa deskripsi seperti itu melalui kode (hardcode) dalam sistem nyata akan sedikit berguna. Kecuali untuk beberapa proses kantor. Jauh lebih menarik untuk dapat menyimpan sirkuit secara terpisah. Minimal, kami tidak perlu memasang kembali proyek setiap kali kami perlu mengubah sesuatu dalam proses atau menambahkan yang baru. Wf core menyediakan fitur ini dengan menyimpan skema json. Kami terus memperluas contoh kami.
Deskripsi proses Json
Lebih lanjut saya tidak akan memberikan deskripsi melalui kode. Ini tidak terlalu menarik, dan hanya akan mengembang artikel.
Wf core mendukung deskripsi skema di json. Menurut pendapat saya, json lebih visual daripada xaml (topik yang bagus untuk holivar di komentar :)). Struktur file sangat sederhana:
{ "Id": "SomeWorkflow", "Version": 1, "DataType": "App.ProcessContext, App", "Steps": [ { /*step1*/ }, { /*step2*/ } ] }
Bidang DataType menunjukkan nama kelas konteks yang sepenuhnya memenuhi syarat dan nama majelis yang dijelaskan. Langkah menyimpan koleksi semua langkah dalam proses. Isi elemen Langkah :
{ "Id": "SomeWorkflow", "Version": 1, "DataType": "App.ProcessContext, App", "Steps": [ { "Id": "Eval", "StepType": "App.CustomStep, App", "NextStepId": "Output", "Inputs": { "Input1": "data.Number1", "Input2": "data.Number2" }, "Outputs": { "StepResult": "step.Result" } }, { "Id": "Output", "StepType": "App.OutputStep, App", "Inputs": { "TextToOutput": "data.StepResult" } } ] }
Mari kita lihat lebih dekat struktur deskripsi langkah via json.
Bidang Id dan NextStepId menyimpan pengidentifikasi langkah ini dan indikator langkah mana yang mungkin berikutnya. Apalagi urutan elemen-elemen koleksi tidak penting.
StepType mirip dengan bidang DataType , ini berisi nama lengkap kelas step (tipe yang mewarisi dari StepBody dan mengimplementasikan logika langkah) dan nama majelis. Lebih menarik adalah objek Input dan Output . Mereka diatur dalam bentuk pemetaan.
Dalam hal Input, nama elemen json adalah nama bidang kelas dari langkah kami; nilai elemen adalah nama bidang di kelas, konteks proses.
Untuk Output, sebaliknya, nama elemen json adalah nama bidang dalam kelas, konteks proses; nilai elemen adalah nama bidang kelas dari langkah kami.
Mengapa bidang konteks ditentukan melalui data. {Field_name} , dan dalam hal Output , langkah. {Field_name} ? Karena wf inti, nilai elemen dieksekusi sebagai ekspresi C # ( Dynamic Expressions library digunakan). Ini adalah hal yang agak berguna, dengan bantuannya Anda dapat meletakkan beberapa logika bisnis langsung di dalam skema, jika, tentu saja, arsitek menyetujui aib seperti itu :).
Kami mendiversifikasi skema dengan primitif standar. Tambahkan langkah kondisional If dan proses peristiwa eksternal.
Jika
Primitif Jika . Di sini kesulitan dimulai. Jika Anda terbiasa dengan bpmn dan menggambar proses dalam notasi ini, maka Anda akan menemukan pengaturan yang mudah. Menurut dokumentasi, langkah tersebut dijelaskan sebagai berikut:
{ "Id": "IfStep", "StepType": "WorkflowCore.Primitives.If, WorkflowCore", "NextStepId": "nextStep", "Inputs": { "Condition": "<<expression to evaluate>>" }, "Do": [ [ { /*do1*/ }, { /*do2*/ } ] ] }
Tidak ada perasaan ada yang salah di sini? Saya punya satu. Input langkah diatur ke Kondisi - ekspresi. Selanjutnya, kita mengatur daftar langkah-langkah di dalam Do array (tindakan). Jadi, di mana cabang Salah ? Mengapa tidak ada Do array untuk False? Sebenarnya ada. Dipahami bahwa cabang False hanyalah sebuah pass lebih jauh di sepanjang proses, yaitu, mengikuti pointer di NextStepId . Pada awalnya, saya selalu bingung karena ini. Oke, bereskan. Meski tidak. Jika proses tindakan dalam kasus True perlu dimasukkan ke dalam Do , inilah json yang "cantik" nantinya. Dan jika ada ini Jika tertutup dengan selusin? Semuanya akan berjalan menyamping. Mereka juga mengatakan bahwa skema pada xaml sulit dibaca. Ada hack kecil. Hanya bawa monitor lebih lebar. Disebutkan sedikit di atas bahwa urutan langkah-langkah dalam koleksi tidak masalah, transisi mengikuti tanda-tanda. Itu bisa digunakan. Tambahkan satu langkah lagi:
{ "Id": "Jump", "StepType": "App.JumpStep, App", "NextStepId": "" }
Coba tebak apa yang saya tuju? Benar, kami memperkenalkan langkah layanan, yang dalam perjalanan membawa proses ke langkah di NextStepId .
Perbarui skema kami:
{ "Id": "SomeWorkflow", "Version": 1, "DataType": "App.ProcessContext, App", "Steps": [ { "Id": "Eval", "StepType": "App.CustomStep, App", "NextStepId": "MyIfStep", "Inputs": { "Input1": "data.Number1", "Input2": "data.Number2" }, "Outputs": { "StepResult": "step.Result" } }, { "Id": "MyIfStep", "StepType": "WorkflowCore.Primitives.If, WorkflowCore", "NextStepId": "OutputEmptyResult", "Inputs": { "Condition": "!String.IsNullOrEmpty(data.StepResult)" }, "Do": [ [ { "Id": "Jump", "StepType": "App.JumpStep, App", "NextStepId": "Output" } ] ] }, { "Id": "Output", "StepType": "App.OutputStep, App", "Inputs": { "TextToOutput": "data.StepResult" } }, { "Id": "OutputEmptyResult", "StepType": "App.OutputStep, App", "Inputs": { "TextToOutput": "\"Empty result\"" } } ] }
Langkah Jika memeriksa untuk melihat apakah hasil dari langkah Eval kosong. Jika tidak kosong, maka kami tampilkan hasilnya, jika kosong, maka pesan " Empty result ". Langkah Langsung membawa proses ke langkah Output , yang berada di luar koleksi Do. Dengan demikian, kami telah mempertahankan "vertikalitas" skema tersebut. Juga, dengan cara ini, seseorang dapat melompat n langkah mundur, mis. untuk mengatur siklus. Ada built-in primitif untuk loop di wf core, tetapi mereka tidak selalu nyaman. Dalam bpmn, misalnya, loop diatur melalui If .
Gunakan pendekatan atau standar ini, terserah Anda. Bagi kami, organisasi seperti itu adalah langkah yang lebih mudah.
Menunggu
Primitif WaitFor memungkinkan dunia luar untuk memengaruhi proses ketika sudah berjalan. Sebagai contoh, jika pada tahap proses persetujuan dari kursus lebih lanjut oleh setiap pengguna diperlukan. Proses akan berdiri pada langkah WaitFor sampai menerima acara yang dilangganinya.
Struktur primitif:
{ "Id": "Wait", "StepType": "WorkflowCore.Primitives.WaitFor, WorkflowCore", "NextStepId": "NextStep", "CancelCondition": "If(cancel==true)", "Inputs": { "EventName": "\"UserAction\"", "EventKey": "\"DoSum\"", "EffectiveDate": "DateTime.Now" } }
Saya akan menjelaskan parameternya sedikit.
CancelCondition - syarat untuk menginterupsi penantian. Memberikan kemampuan untuk menginterupsi penantian suatu acara dan melanjutkan prosesnya. Sebagai contoh, jika suatu proses menunggu n peristiwa yang berbeda pada saat yang sama (jika inti mendukung pelaksanaan langkah-langkah paralel), tidak perlu menunggu semua tiba , dalam hal ini CancelCondition akan membantu kami . Kami menambahkan flag logis ke variabel konteks dan setelah menerima acara kami mengatur flag menjadi true - semua langkah WaitFor selesai.
EventName dan EventKey - nama dan kunci acara. Bidang diperlukan untuk membedakan peristiwa, mis., Dalam sistem nyata dengan sejumlah besar proses yang bekerja secara bersamaan. sehingga mesin mengerti acara apa yang dimaksudkan untuk proses apa dan langkah apa.
EffectiveDate - bidang opsional yang menambahkan cap waktu acara. Ini mungkin berguna jika Anda perlu mempublikasikan acara "ke masa depan". Agar segera dipublikasikan, Anda dapat membiarkan parameter kosong atau mengatur waktu saat ini.
Tidak dalam semua kasus, lebih baik mengambil langkah terpisah untuk memproses reaksi dari luar, bahkan biasanya akan berlebihan. Langkah tambahan dapat dihindari dengan menambahkan harapan dari peristiwa eksternal dan logika pemrosesannya ke langkah biasa. Kami melengkapi langkah CustomStep dengan berlangganan ke acara eksternal:
public class CustomStep : StepBody { private readonly Ilogger _log; public string TextToOutput { get; set; } public CustomStep(Ilogger log) { _log = log; } public override ExecutionResult Run(IStepExecutionContext context) {
Kami menggunakan metode ekstensi WaitForEvent () standar. Ini menerima parameter yang disebutkan sebelumnya EventName , EventKey dan EffectiveDate . Setelah menyelesaikan logika langkah tersebut, proses akan menunggu acara yang dijelaskan dan kembali memanggil metode Run () pada saat acara tersebut diterbitkan di bus mesin. Namun, dalam formulir saat ini, kami tidak dapat membedakan antara saat-saat entri awal ke langkah dan entri setelah acara. Tetapi saya ingin memisahkan logika sebelum-setelah pada tingkat langkah. Dan bendera EventPublished akan membantu kita dengan ini. Itu terletak di dalam konteks umum proses, Anda bisa mendapatkannya seperti ini:
var ifEvent=context.ExecutionPointer.EventPublished;
Berdasarkan bendera ini, Anda dapat dengan aman membagi logika menjadi sebelum dan sesudah peristiwa eksternal.
Klarifikasi penting - sesuai dengan ide pembuat mesin, satu langkah hanya dapat ditandatangani pada satu acara dan bereaksi sekali saja. Untuk beberapa tugas, ini adalah batasan yang sangat tidak menyenangkan. Kami bahkan harus "menyelesaikan" mesin untuk melepaskan diri dari nuansa ini. Kami akan melewatkan deskripsi mereka di artikel ini, kalau tidak artikel itu tidak akan pernah berakhir :). Praktik penggunaan yang lebih kompleks dan contoh peningkatan akan dibahas dalam artikel selanjutnya.
Proses pendaftaran di mesin. Publikasi acara di bus.
Jadi, dengan implementasi logika langkah-langkah dan deskripsi proses dipecahkan. Yang tersisa adalah hal yang paling penting, yang tanpanya proses tidak akan berfungsi - deskripsi perlu didaftarkan.
Kami akan menggunakan metode ekstensi AddWorkflow () standar, yang akan menempatkan dependensinya dalam wadah IoC kami.
Ini terlihat seperti ini:
public static IServiceCollection AddWorkflow(this IServiceCollection services, Action<WorkflowOptions> setupAction = null)
IServiceCollection - interface - kontrak untuk kumpulan deskripsi layanan. Dia tinggal di dalam DI dari Microsoft (lebih lanjut tentang itu dapat dibaca di sini )
WorkflowOptions - pengaturan engine dasar. Tidak perlu mengaturnya sendiri, nilai standar cukup dapat diterima untuk kenalan pertama. Kita melangkah lebih jauh.
Jika prosesnya dijelaskan dalam kode, maka pendaftaran terjadi seperti ini:
var host = _serviceProvider.GetService<IWorkflowHost>(); host.RegisterWorkflow<SomeWorkflow, ProcessContext>();
Jika proses dijelaskan melalui json, maka harus didaftarkan sebagai berikut (tentu saja, deskripsi json harus dimuat dari lokasi penyimpanan):
var host = _serviceProvider.GetService<IWorkflowHost>(); var definitionLoader = _serviceProvider.GetService<IDefinitionLoader>(); var definition = loader.LoadDefinition({*json *});
Lebih lanjut, untuk kedua opsi, kode akan sama:
host.Start();
Parameter definitionId adalah pengidentifikasi proses. Apa yang tertulis di kolom Id proses. Dalam hal ini, id = SomeWorkflow .
Parameter versi menentukan versi proses yang akan dijalankan. Mesin menyediakan kemampuan untuk segera mendaftar di versi proses dengan satu pengidentifikasi. Ini nyaman ketika Anda perlu membuat perubahan pada deskripsi proses tanpa melanggar tugas yang sudah berjalan - yang baru akan dibuat sesuai dengan versi baru, yang lama akan hidup diam-diam pada yang lama.
Parameter konteks adalah turunan dari konteks proses.
Metode host.Start () dan host.Stop () memulai dan menghentikan proses hosting. Jika dalam aplikasi peluncuran proses adalah tugas yang diterapkan dan dilakukan secara berkala, maka hosting harus dihentikan. Jika aplikasi memiliki fokus utama pada implementasi berbagai proses, maka hosting tidak dapat dihentikan.
Ada metode untuk mengirim pesan dari dunia luar ke bus mesin, yang kemudian akan mendistribusikannya di antara pelanggan:
Task PublishEvent(string eventName, string eventKey, object eventData, DateTime effectiveDate = null);
Deskripsi parameternya lebih tinggi di artikel ( lihat bagian primitif WaitFor ).
Kesimpulan
Kami benar-benar mengambil risiko ketika kami memutuskan untuk mendukung Workflow Core - proyek opensource, yang secara aktif dikembangkan oleh satu orang, dan bahkan dengan dokumentasi yang sangat buruk. Dan Anda kemungkinan besar tidak akan menemukan praktik nyata menggunakan inti WF dalam sistem produksi (kecuali milik kami). Tentu saja, setelah memilih lapisan abstraksi yang terpisah, kami mengasuransikan diri terhadap kasus kegagalan dan kebutuhan untuk segera kembali ke WWF, misalnya, atau solusi yang ditulis sendiri, tetapi semuanya berjalan dengan baik dan kegagalan tidak datang.
Beralih ke engine Core Alur Kerja opensource memecahkan sejumlah masalah yang mencegah kami hidup damai di WWF. Yang paling penting di antara mereka adalah, tentu saja, mendukung .Net Core dan tidak adanya WWF.
Berikut ini adalah sumber terbuka. Bekerja dengan WWF dan mendapatkan berbagai kesalahan dari perutnya, kemampuan untuk setidaknya membaca sumbernya akan sangat membantu. Belum lagi mengubah sesuatu di dalamnya. Di sini, dengan Workflow Core, kebebasan penuh (termasuk lisensi - MIT). Jika kesalahan tiba-tiba muncul dari perut mesin, cukup unduh sumber dari github dan dengan tenang mencari penyebab kemunculannya. Ya, hanya kemampuan untuk menghidupkan mesin dalam mode debug dengan breakpoint sudah sangat memudahkan proses.
Tentu saja, memecahkan beberapa masalah, Workflow Core membawa yang baru. Kami harus melakukan sejumlah besar perubahan pada inti mesin. Tapi Bekerja pada "penyelesaian" untuk diri mereka sendiri lebih murah dalam waktu daripada mengembangkan mesin Anda sendiri dari awal. Solusi akhir cukup dapat diterima dalam hal kecepatan dan stabilitas, itu memungkinkan kami untuk melupakan masalah dengan mesin dan fokus pada pengembangan nilai bisnis produk.
PS Jika topiknya ternyata menarik, maka akan ada lebih banyak artikel tentang inti, dengan analisis yang lebih dalam dari mesin dan solusi untuk masalah bisnis yang kompleks.