Tugas eksternal Camunda - alat yang ampuh untuk membangun aplikasi dengan arsitektur yang tangguh dan dapat diskalakan

gambar

Di Tinkoff, kami menggunakan kerangka kerja Camunda + Spring untuk mengembangkan sistem otomasi proses bisnis . Kami menjelaskan proses bisnis menggunakan BPMN (Notasi Manajemen Proses Bisnis) dalam bentuk bagan alur.

Elemen yang paling umum digunakan dalam diagram kami adalah tugas servis (gear rectangle). Camunda mendukung dua cara untuk melakukan tugas layanan :

  1. Menggunakan panggilan sinkron ke kode java.
  2. Membuat tugas eksternal.

Metode kedua memungkinkan Anda untuk melakukan tugas menggunakan sistem eksternal - misalnya, jika Anda perlu memanggil satu aplikasi camunda dari yang lain atau bahkan mendelegasikan pekerjaan ke sistem eksternal mana pun.

gambar
Contoh Diagram BPMN

Ini berguna ketika Anda bermaksud untuk menggunakan kembali logika di beberapa aplikasi. Atau ketika Anda ingin tetap berpegang pada arsitektur microservice. Misalnya, memisahkan layanan yang berhubungan dengan proses bisnis dari layanan yang mengimplementasikan tugas teknis, seperti menghasilkan laporan atau pengiriman surat.

Bersamaan dengan fitur ini, tugas eksternal memberikan arsitektur yang tangguh dan dapat diskalakan. Untuk memahami mengapa hal ini terjadi, Anda harus terlebih dahulu memahami bagaimana tugas eksternal bekerja di tingkat BPMN dan aplikasi.

Tugas eksternal di BPMN


Tugas eksternal melibatkan pembuatan tugas yang dapat dilakukan oleh penangan eksternal. Inti dari pola tugas eksternal adalah:

  1. , ยซยป , ยซยป.
  2. camunda , , .
  3. camunda (/).

Dalam diagram di atas, saya menggambarkan proses fiksi di mana kami ingin mendapatkan daftar pengguna, mengirimkan iklan kepada mereka dan setelah 2 jam menghitung jumlah aplikasi setelah buletin pemasaran. Dan, jika ada lebih dari 10 aplikasi, tingkatkan pilihan untuk pengiriman berikutnya.

Saya ingin aplikasi camunda saya hanya bertanggung jawab untuk proses bisnis, dan aplikasi lain mana pun harus bertanggung jawab untuk mengirim email. Dalam hal ini, pola tugas eksternal berfungsi dengan baik untuk saya . Dalam proses saya, saya hanya akan membuat tugas buletin email dan menunggu sampai diselesaikan oleh beberapa penangan eksternal.

Untuk membuat tugas eksternal dalam diagram , Anda harus:

  1. Buat tugas biasa .
  2. Ubah tipenya menjadi tugas layanan .
  3. Tetapkan implementasi ke eksternal .
  4. Tentukan nilai bidang Topik .

gambar

Topik adalah nama antrian di mana tugas-tugas dari satu jenis akan ditambahkan dan ke mana pengendali eksternal akan berlangganan.

Sekarang ada tugas eksternal dalam proses , Anda dapat memulainya, tetapi tidak akan dieksekusi, karena tidak ada yang memprosesnya.

Pekerja tugas eksternal


Pola tugas eksternal baik karena memungkinkan Anda untuk mengimplementasikan pemrosesan tugas dalam bahasa apa pun, menggunakan alat apa pun yang dapat melakukan permintaan HTTP .

Berikut ini adalah contoh dari blog camunda . Contoh ini mengimplementasikan penangan javascript eksternal yang, setiap 20 detik, meminta daftar tugas pemrosesan dari camunda . Jika ada tugas, maka itu mengirim mereka keluar dan memberi tahu camunda tentang penyelesaian tugas.

const baseUrl = 'http://localhost:8080/my-app/rest';
const workerSettings = {
 workerId: 'worker01', // some unique name for the current worker instance
 maxTasks: 5,
 topics: [
   {
     topicName: 'sendEmail',
     lockDuration: 10000, // How much time the worker thinks he needs to process the task
     variables: ['video'] // Which variables should be returned in the response (to avoid additional REST calls to read data)
   }]};
const requestParams = {method: 'POST', headers: {contentType: 'application/json'}};

function pollExternalTasks() {
 return fetch(`${baseUrl}/external-task/fetchAndLock`, {
   ...requestParams,
   body: JSON.stringify(workerSettings)
 })
}

function processExternalTask(result = []) {
 return Promise.all(result.map(externalTask => {
   sendEmail(externalTask); // Here the actual work would be done

   return fetch(`${baseUrl}/external-task/${externalTask.id}/complete`, {
     ...requestParams,
     body: JSON.stringify({workerId: workerSettings.workerId}),
   })
 }));
}

setInterval(() => {
 pollExternalTasks().then(processExternalTask)
}, 20000);

Seperti yang dapat Anda lihat dari kode di atas, metode utama untuk menangani tugas eksternal adalah fetchAndLock dan selesai . Metode pertama meminta daftar tugas dan mengamankan implementasinya, dan yang kedua menginformasikan tentang penyelesaian tugas. Selain kedua metode ini, ada metode lain, Anda dapat membacanya di dokumentasi resmi .

Camunda klien tugas eksternal


gambar

Untuk menerapkan pemrosesan tugas eksternal , camunda menyediakan Javascript dan klien Java yang memungkinkan Anda membuat penangan tugas eksternal hanya dalam beberapa baris. Ada juga panduan terperinci yang menjelaskan prinsip-prinsip dasar pemrosesan tugas eksternal - lagi dengan contoh dalam Javascript dan Java .

Contoh penerapan penangan eksternal menggunakan ExternalTaskClient :

public class App {
   public static void main(String... args) {
       // bootstrap the client
       ExternalTaskClient client = ExternalTaskClient.create()
           .baseUrl("http://localhost:8080/engine-rest")
           .asyncResponseTimeout(1000)
           .build();

       // subscribe to the topic
       client.subscribe("sendEmail").handler((externalTask, externalTaskService) -> {
           try {
               String result = sendEmail(externalTask)
               Map<String, Object> variables = new HashMap<>();

               variables.put("result", result);
               externalTaskService.complete(externalTask, variables);
               System.out.println("The External Task " + externalTask.getId() + " has been completed!");
           } catch (e: Exception) {
               externalTaskService.handleFailure(externalTask, e.message, e.stackTrace.toString())
           }
       }).open();
   }
}

Jika tugas Anda mengharuskan tidak hanya melakukan beberapa tindakan sinkron, tetapi memulai seluruh proses, maka Anda dapat melakukannya, misalnya, dengan memulai proses melalui RuntimeService :

@Service
class EmailWorker(
   private val runtimeService: RuntimeService
) {
   val builder = ExternalTaskClientBuilderImpl().baseUrl("http://localhost:8080").workerId("myWorker")
   val taskClient = builder.build()
   val engineClient = (builder as ExternalTaskClientBuilderImpl).engineClient

   @PostConstruct
   fun init() {
       taskClient
           .subscribe("sendEmail")
           .lockDuration(10000)
           .handler { externalTask, externalService ->
               runtimeService.startProcessInstanceByKey(
                   "SendEmailProcess",
                   externalTask.getVariable("emailId"),
                   mapOf(
                       "text" to externalTask.getVariable("text"),
                       "email" to externalTask.getVariable("email")
                   )
               )
           }
           .open()
   }


   @PreDestroy
   fun destroy() {
       taskClient.stop()
   }
}

// Delegate from SendEmailProcess process
@Component
class EmailResultDelegate(private val emailWorker: EmailWorker) {
   fun doExecute(execution: DelegateExecution) {
       emailWorker.engineClient.complete(
           execution.readVar(EXTERNAL_TASK_ID),
           mapOf("result" to "Success")
       )
   }
}

Dalam contoh ini, penangan tugas eksternal ( EmailWorker ), ketika tugas diterima, memulai proses SendEmailProcess .

Bayangkan proses ini melakukan beberapa tindakan yang diperlukan untuk mengirim nawala, dan pada akhirnya memanggil EmailResultDelegate , yang, pada gilirannya, menyelesaikan tugas eksternal .

Manfaat Arsitektur dari Tugas Eksternal


Perlu dicatat bahwa ada cara untuk memulai proses dalam aplikasi camunda lain dengan cara yang lebih sederhana: POST: / rest / process-definition / key / $ {id} / start

Ketika Anda menggunakan REST , Anda tidak memiliki jaminan transaksi. Tapi bagaimanapun, kami juga bekerja dengan tugas eksternal melalui REST , apa bedanya?

Perbedaannya adalah bahwa kita tidak memanggil layanan eksternal secara langsung, tetapi hanya mempublikasikan tugas yang dapat diproses. Pertimbangkan sebuah contoh:

gambar

Beberapa penangan eksternal mengambil tugas yang sekarang ditugaskan kepadanya, tetapi ketika respons diterima, koneksi terputus. Sekarang di sisi camundatugas yang tidak akan diproses diblokir karena penangan eksternal tidak menerima respons. Tapi ini tidak menakutkan: di camunda untuk tugas-tugas eksternal ada batas waktu dimana tugas akan kembali ke antrian lagi dan orang lain dapat mengatasinya.

Sekarang mari kita lihat kasus ketika penangan eksternal menerima tugas, menyelesaikannya, dan memanggil metode lengkap , yang gagal karena masalah jaringan. Sekarang Anda tidak akan dapat memahami apakah tugas itu berhasil diselesaikan di camunda atau tidak. Anda dapat mencoba lagi, tetapi ada kemungkinan masalah jaringan akan berlanjut.

Dalam hal ini, solusi terbaik adalah dengan mengabaikan masalahnya. Jika tugas berhasil diselesaikan, maka semuanya beres. Jika tidak, setelah batas waktu tugas akan tersedia lagi untuk diproses. Tetapi ini berarti bahwa pawang eksternal Anda harus idempoten atau mengandung logika untuk menduplikasi tugas.

Masalah serupa dapat terjadi ketika memulai proses baru, jadi Anda harus memeriksa contoh yang ada dengan data yang sama, misalnya, businessKey .

Selain tugas eksternal toleransi kesalahan tinggimemungkinkan Anda untuk skala penangan eksternal dengan mudah dan menerapkannya dalam bahasa pemrograman apa pun. Pada saat yang sama, polanya membantu untuk mengimplementasikan layanan-layanan mikro sehingga mereka saling memengaruhi sesedikit mungkin, sehingga meningkatkan stabilitasnya.

Lebih lanjut tentang tugas eksternal :
https://docs.camunda.org/manual/latest/user-guide/process-engine/external-tasks/
https://docs.camunda.org/manual/latest/reference/rest/external -task /
https://docs.camunda.org/manual/latest/user-guide/ext-client/

All Articles