ํค์ด ํ๋ธ๋ฅด! ๋๋ ๊ธฐ์ฌ์ ๋ฒ์ญ์ ๋น์ ์ ๊ด์ฌ์ ์ ์ํฉ๋๋ค
07.07.2020๋
XNUMX์ XNUMX์ผ, ๋ฒ์ญ
์ ๋ ์ข ์ข Java๊ฐ ์๋ C# ๊ฐ๋ฐ์, Node.JS/JavaScript ๊ฐ๋ฐ์ ๋๋ Golang ์ ํธ๊ฐ์ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ ๋ํด ๋ ผ์ํฉ๋๋ค. ์ด๋ค ๋ชจ๋๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ ์ค์ผ์คํธ๋ ์ด์ ๋ฉ์ปค๋์ฆ์ด ํ์ํ๊ฑฐ๋ ์ํฌํ๋ก๋ฅผ ๊ฐ์ํํ๊ณ ์ฃผ๋ฌธ, ์๊ฐ ์ด๊ณผ ์ฒ๋ฆฌ, Saga ๋ฐ ๋ณด์ ํธ๋์ญ์ ๊ธฐ๋ฅ์ ์ป๊ธฐ ์ํ ๋๊ตฌ๊ฐ ํ์ํ๋ค๋ ์ฌ์ค์ ์ง๋ฉดํด ์์ต๋๋ค.
BPM ํ๋ซํผ
์๋์! ์ค์ ๋ก Java ์ง์ ์์ด๋ Camunda๋ฅผ ์ฝ๊ฒ ์คํํ ์ ์์ผ๋ฉฐ ์ํ๋ ์ธ์ด๋ก ์ฝ๋ ์ํคํ ์ฒ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค. ์ด ๊ธฐ์ฌ์์๋ ๋ค์์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
- ๊ธฐ๋ณธ ์ํคํ ์ฒ;
- REST API
- Java ์ด์ธ์ ์ธ์ด์ ๋ํ ๊ธฐ์กด ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์กฐ์ธ
- C# ๋ฐ Node.JS๋ฅผ ์ฌ์ฉํ ์;
- Camunda ์๋ฒ(Docker ๋๋ Tomcat)๋ฅผ ์์ํ๋ ๋ฐฉ๋ฒ.
๊ตฌ์กฐ
Camunda๋ Java๋ก ์์ฑ๋์์ผ๋ฉฐ ์คํํ๋ ค๋ฉด JVM(Java Virtual Machine)์ด ํ์ํฉ๋๋ค. Camunda๋ ์ํ๋ ์ธ์ด๋ก ์์ฑํ๊ณ Camunda์ ํจ๊ป REST๋ฅผ ์ฌ์ฉํ ์ ์๋ REST API๋ฅผ ์ ๊ณตํฉ๋๋ค.
Camunda์ ์ํฌํ๋ก์ฐ๋ ๊ธฐ๋ณธ์ ์ผ๋ก XML ํ์ผ์ธ BPMN์ผ๋ก ์ ์๋ฉ๋๋ค. ์ผ๋ก ๋ชจ๋ธ๋งํ ์ ์์ต๋๋ค.
์ฌ์ ๋น๋๋ Docker ์ด๋ฏธ์ง๋ฅผ ํตํด Camunda ์คํ
Camunda๋ฅผ ์คํํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ Docker๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. Camunda๋ฅผ ์์ํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ด ๋ฌธ์์ ๋ท๋ถ๋ถ์์ ์ค๋ช ํฉ๋๋ค.
์ด ๊ฒฝ์ฐ ๊ฐ๋จํ ๋ค์์ ์คํํ์ญ์์ค.
docker run -d -p 8080:8080 camunda/camunda-bpm-platform:latest
Linux, JVM ๋๋ Tomcat์ ๋ํด ๊ฑฑ์ ํ ํ์๊ฐ ์์ต๋๋ค. Dockerfile ๋ฐ ๊ธฐ๋ณธ ๋ฌธ์(์: ํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ง์นจ)๋ ๋ค์์์ ํ์ธํ ์ ์์ต๋๋ค.
Camunda Enterprise Edition์ ์คํํ๋ ค๋ฉด ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค
๊ทธ๋ฌ๋ Docker๋ก Camunda๋ฅผ ์คํํ๋ฉด ํ ๊ฐ์ง ๋จ์ ์ด ์์ต๋๋ค. ์ฆ, ํญ์ ์ต์ ์์ ์ฌํญ์ด ํฌํจ๋์ง ์๋ Tomcat ๋ฒ์ ์ด ์์ฑ๋๋ค๋ ๊ฒ์ ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ด ์์ ์ ํ์๋ ๋๋ก ์ํ๋ Tomcat ๋ฐฐํฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ์ ํ Docker ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ฑฐ๋ ์๋ ์ค๋ช ๋ ์๋ฃจ์ ์ค ํ๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ๋ก์ธ์ค ๋ชจ๋ธ ๋ฐฐํฌ
์ธ ๊ฐ์ง ์์ ์ ์ฐ์์ผ๋ก ํธ๋ฆฌ๊ฑฐํ๊ณ ๋์ค์ ์คํจํ ๊ฒฝ์ฐ ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ์์ ์ ์ ์ ํ๊ฒ ๋ณด์ํ๋ ค๋ ์ผ๋ฐ์ ์ธ ์ฌํ ์์ฝ์ Saga ํ ํ๋ฆฟ์ ์ฌ์ฉํ๋ ์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. BPMN ํ์์ผ๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
curl -w "n"
-H "Accept: application/json"
-F "deployment-name=trip"
-F "enable-duplicate-filtering=true"
-F "deploy-changed-only=true"
-F "[email protected]"
http://localhost:8080/engine-rest/deployment/creat
์ด์ ์คํํ ์ ์์ต๋๋ค
curl
-H "Content-Type: application/json"
-X POST
-d '{"variables":{"someData" : {"value" : "someValue", "type": "String"}},"businessKey" : "12345"}}'
http://localhost:8080/engine-rest/<!-- -->process-definition/key/<!-- -->FlowingTripBookingSaga<!-- -->/start
๋ค์ ํฅ๋ฏธ๋ก์ด ์ง๋ฌธ์ Camunda๊ฐ ์๋์ฐจ ์์ฝ๊ณผ ๊ฐ์ ์ ์ฐจ๋ฅผ ์ด๋ป๊ฒ ํธ์ถํ๋๊ฐ์
๋๋ค. Camunda๋ ๋ด์ฅ๋ ์ผ๋ถ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ฆ์ ์๋น์ค๋ฅผ ํธ์ถํ ์ ์์ ๋ฟ๋ง ์๋๋ผ(Push-Principle)
๋จผ์ ์คํํด์ผํฉ๋๋ค
curl
-H "Content-Type: application/json"
-X POST
-d <!-- -->'{"workerId":"worker123","maxTasks":1,"usePriority":true,"topics":[{"topicName": "reserve-car"}, "lockDuration": 10000, "variables": ["someData"]}]}'<!-- -->
http://localhost:8080/engine-rest/external-task/fetchAndLock
๊ทธ๋ผ Camunda์๊ฒ ๋งํด์ค
curl
-H "Content-Type: application/json"
-X POST
-d <!-- -->'{"workerId":"worker123", "variables": {}}'<!-- -->
http://localhost:8080/engine-rest/<!-- -->external-task/EXTERNAL_TASK_ID/complete
๊ทธ๊ฒ ๋ค์ ๋๋ค. ์์ง Java๊ฐ ํ์ํ์ง ์์ต๋๋ค. ๊ทธ๋ ์ฃ ? ์์ํ๊ธฐ์ ์ถฉ๋ถํฉ๋๋ค!
ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
REST API๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ชจ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ฝ์ต๋๋ค. JavaScript์์๋ JQuery๋ฅผ ์ฌ์ฉํ๊ณ C#์์๋ System.Net.Http ๋ฐ Newtonsoft.Json์ ์ฌ์ฉํ์ฌ ์ด ์์ ์ ํธ๋ฆฌํ๊ฒ ์ํํฉ๋๋ค. ํ์ง๋ง ์๊ฐ์ด ์ข ๊ฑธ๋ฆด ๊ฑฐ์์. ๋ฐ๋ผ์ ์ผ๋ถ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ์ฌ ๋ช ๊ฐ์ง ๊ธฐ์ฑ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์๋ฐ ์คํฌ๋ฆฝํธ :
๋งํฌ . Camunda์ ์ง์; - ์๋ฐ :
๋งํฌ . Camunda์ ์ง์; - ์จ#:
๋งํฌ ะธ๋งํฌ . ์ด ๋ ํ๋ก์ ํธ๋ ๋ชจ๋ ์ค๊ฐ ์ํ์ ์์ผ๋ฉฐ ์ฌ์ค์ ํด๋ฉด ์ํ์ด์ง๋ง ์ข์ ์ถ๋ฐ์ ์ด ๋ ์ ์์ต๋๋ค. - PHP :
๋งํฌ - ๋๋ฌด ์์ ํ์ง๋ ์๊ณ ์ต์ API ๋ณ๊ฒฝ ์ฌํญ๋ ํฌํจํ์ง ์์ง๋ง ์ด๋ฅผ ์ฌ์ฉํ๋ ํ๋ก์ ํธ๋ฅผ ์๊ณ ์์ต๋๋ค.
JavaScript ๋ฐ Java๋ฅผ ์ ์ธํ๊ณ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Camunda ์ ํ ์์ฒด์ ์ผ๋ถ๊ฐ ์๋๋๋ค. Camunda์ REST API ๊ธฐ๋ฅ์ ๋ชจ๋ ์ง์ํ ๊ฒ์ด๋ผ๊ณ ๊ธฐ๋ํ์ง ๋ง์ญ์์ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํน์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์๋๋ค๊ณ ํด์ ๊ทธ๊ฒ์ด ์กด์ฌํ์ง ์๋๋ค๋ ๊ฒ์ ์๋ฏธํ์ง๋ ์์ต๋๋ค. ํญ์ Camunda์ REST API๋ฅผ ํ์ธํ์ธ์. ์ฐธ์กฐ ํ๋ก์ ํธ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์์ ๊ณผ ํ ํ๋ฆฟ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
C# ์
์์ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ๋จํ ์์ฑํ ์ ์์ต๋๋ค.
var camunda = new CamundaEngineClient("http://localhost:8080/engine-rest/engine/default/", null, null);
// Deploy the BPMN XML file from the resources
camunda.RepositoryService.Deploy("trip-booking", new List<object> {
FileParameter.FromManifestResource(Assembly.GetExecutingAssembly(), "FlowingTripBookingSaga.Models.FlowingTripBookingSaga.bpmn")
});
// Register workers
registerWorker("reserve-car", externalTask => {
// here you can do the real thing! Like a sysout :-)
Console.WriteLine("Reserving car now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
registerWorker("cancel-car", externalTask => {
Console.WriteLine("Cancelling car now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
registerWorker("book-hotel", externalTask => {
Console.WriteLine("Reserving hotel now...");
camunda.ExternalTaskService.Complete(workerId, externalTask.Id);
});
// Register more workers...
StartPolling();
string processInstanceId = camunda.BpmnWorkflowService.StartProcessInstance("FlowingTripBookingSaga", new Dictionary<string, object>()
{
{"someBookingData", "..." }
});
์์ ํ ์๋ํ๋ ์์ค ์ฝ๋๋ ์จ๋ผ์ธ์์ ์ฐพ์ ์ ์์ต๋๋ค.
Node.js์ ์
var Workers = require('camunda-worker-node');
var workers = Workers('http://localhost:8080/engine-rest', {
workerId: 'some-worker-id'
});
workers.registerWorker('reserve-car', [ 'someData' ], function(context, callback) {
var someNewData = context.variables.someData + " - added something";
callback(null, {
variables: {
someNewData: someNewData
}
});
});
workers.shutdown();
๋ ๋ง์ ์ ๋ณด๋ ํํ์ด์ง์์ ํ์ธํ์ค ์ ์์ต๋๋ค
Camunda๋ฅผ ์์ํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ
"Camunda ๋ ๋ฆฝํ WAR"์ด ํฌํจ๋ ์ฌ์ฉ์ ์ ์ Docker ์ด๋ฏธ์ง
Camunda์ ์ฌ์ ๊ตฌ์ถ๋ Docker ์ด๋ฏธ์ง ๋์ Tomcat์ ์ง์ ์ค๋นํ ๋ค์(์: ๊ณต์ Docker Tomcat ์ด๋ฏธ์ง ๊ธฐ๋ฐ) Camunda๋ฅผ ์์ WAR ํ์ผ ์ค ํ๋๋ก ๋ณต์ฌํ ์ ์์ต๋๋ค.
์ถ๊ฐ ์๊ตฌ ์ฌํญ์ด ๋ง๊ณ Java ๋น๋ ํ๊ฒฝ์ ์ค์ ํ ์ ์๋ ๊ฒฝ์ฐ Camunda Standalone War๋ฅผ ์ค์ ํ ์๋ ์์ต๋๋ค. ๋ค์ ์์์ ๊ฐ์ด Maven ๋น๋๋ฅผ ์ค์ ํฉ๋๋ค.
Camunda Tomcat ๋ฐฐํฌ ์์
๋ ๋ค๋ฅธ ์ต์
์ Camunda Tomcat ๋ฐฐํฌํ์ ๋ค์ด๋ก๋ํ์ฌ ์์ถ์ ํ๊ณ ์คํํ๋ ๊ฒ์
๋๋ค. ์ด๋ฅผ ์ํด์๋ ์ปดํจํฐ์ JRE(Java Runtime Environment)๋ง ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค. ์ฝ๊ฒ ํ ์ ์์ต๋๋ค
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋ค๋ฅธ ์์
์ ์ํํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด Tomcat์ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค.
Tomcat์ ์ฌ์ฉํ์ฌ Camunda ์คํ
๋ง์ง๋ง ๋์์ Tomcat์ ์ง์ ์ค์ ํ๊ณ Camunda๋ฅผ ์ค์นํ๋ ๊ฒ์
๋๋ค.
Camunda๋ฅผ ์์ฐ์ ํฌ์
์ผ๋ฐ์ ์ผ๋ก Camunda๋ฅผ ์คํํ๋ ค๋ฉด ๋ช ๊ฐ์ง ์ต์ข ์ค์ ์ด ํ์ํฉ๋๋ค. Camunda์๋ ์ด์ ๋ํด ์์ธํ ์ค๋ช ํ๋ ์ง์นจ์ด ์์ง๋ง ์ด ๊ธฐ์ฌ์์๋ ์ด์ ๋ํด ๋ค๋ฃจ์ง ์์ ๊ฒ์ ๋๋ค. ์๋ฅผ ํ๋๋ง ๋ค๊ฒ ์ต๋๋ค. ๋ฐฐํฌํ์ REST API๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ์ฆ์ ์ํด ๊ตฌ์ฑ๋์ง ์์ต๋๋ค. ์ด๊ฒ์ ๋ณ๊ฒฝํ๊ณ ์ถ์ ์๋ ์์ต๋๋ค.
ํต๊ณ
๋ณด์๋ค์ํผ, ์ฌ์ฉํ๋ ์ธ์ด์ ๊ด๊ณ์์ด Camunda๋ฅผ ์์ํ๋ ๊ฒ์ ๋งค์ฐ ์ฝ์ต๋๋ค. ์ค์ํ ์ ์ ๋ชจ๋ ์ํธ ์์ฉ์ด REST API๋ฅผ ํตํด ์ํ๋๋ค๋ ๊ฒ์ ๋๋ค. ํนํ Docker๋ฅผ ์ฌ์ฉํ ๋ ์ค์น๋ ๋งค์ฐ ์ฝ์ต๋๋ค.
์ถ์ฒ : habr.com