[BPMN] Service Task with REST-API (PATCH) Example

หลังจาก Blog ตอนก่อน ผมได้ลอง Service Task เชื่อมกับ Web Service ผ่านวิธีการ GET เพื่อที่ดึงข้อมูลมาแสดงผลครับ คราวนี้หลังจาก GET ข้อมูลไปแล้วคราวนี้ เราลองมาทำการแก้ไขข้อมูลครับ ซึ่งการแก้ไขข้อมูลบางส่วน อันนี้ทาง Web Service (REST API) เค้ามีวิธีการที่เรียกว่า PATCH ครับ ส่วนจะทำอย่างไรนั้นมาลุยกันเลยครับ

เตรียมตัวครับ

กระบวนการที่สร้างกันก่อนครับ

  • สำหรับกระบวนการที่สร้างคราวนี้ผมทั้ง JSON Server ขึ้นมาเองครับ โดยใช้ข้อมูล Request ซึ่งผู้ใช้ต้องใส่ ID เพื่อให้ระบบดึงข้อมูล Request ขึ่นมาครับ หลังจากดูเสร็จ แล้วกด Complete ข้อมูลของ Request ในช่อง “requeststatus” ถูกแก้ไขค่าจาก “wait-for-review” เป็น “completed” ครับ

ลองมือทำ โดยมี Task ที่เกี่ยวข้อง ดังนี้

  • Task “Enter Request Id” เป็น User Task เอาไว้สำหรับกรอก Id ของ Request ครับ
  • Task “Test REST-API (GET)” เป็น Service Task ที่ติดต่อกับ Web Service โดยมี Config ดังนี้
    • Connector Id = “http-connector”
    • Input มีค่าตามตารางด้านล่างครับ
      ์NameTypeScript FormatData
      urlscriptgroovy  “http://localhost:3000/requests/${RequestId}”.toString()
      methodtext  GET
      headermap  Key = “Accept”
      Value = “application/json”
    • Output เนื่องจากข้อมูลที่ได้เป็นอยู่ในรูปแบบ JSON จึงต้องมีการแปลงค่า และยัดลง Process ของ BPMN ได้แก่ id, projectid, requestid, requestby และ requeststatus ครับ โดยมี Code ดังนี้
  • Task “View Result” เป็น User Task ที่เอาผลลัพธ์ที่ได้จาก Task “Test REST-API (GET)” มาแสดงผลครับ
    • Connector Id = “http-connector”
    • Input มีค่าตามตาราง
      ์NameTypeScript FormatData
      urlscriptgroovy  “http://localhost:3000/requests/${RequestId}”.toString()
      methodtext  GET
      headermap  Key = “Accept”
      Value = “application/json”
        Key =”Content-Type”
      Value = “application/json”
      payloadscriptgroovy
  • Task “REST-API(PATCH) request status” เป็น Service Task ที่ทำหน้าที่เปลี่ยน “requeststatus” ถูกแก้ไขค่าจาก “wait-for-review” เป็น “completed” ครับ โดยมี Config ดังนี้ครับ
  • เมื่อสร้าง Task เสร็จแล้ว นำไฟล์ BPMN ที่ได้เตรียมไป Deploy ครับ

ทดสอบ

  • เตรียมข้อมูลสำหรับ Mock Server กันก่อนครับ โดยข้อมูลที่ได้มีหน้าตา ดังนี้ (ถูกเก็บไว้ในไฟล์ db.json ครับ)
  • Start JSON Server ด้วยคำสั่ง  json-server --watch db.json
  • เข้าไปที่ Camunda Task List จากนั้น Execute Task ชื่อ “HttpConnectorRequestPatch”
    • กรอก Request Id = 2
    • ดูรายการ Request จากนั้นกดปุ่ม Complete
    • ลองไปดูที่ Console ครับ พบว่า ช่อง “requeststatus” ถูกแก้ไขค่าจาก “wait-for-review” เป็น “completed” แล้วครับ

[BPMN] Service Task with REST-API (Get) Example

หลังจากงมๆมานานพอสมควรแล้วกับการใช้งาน Service Task กับ Web Service กับ Camunda BPMN Engine ครับ โดยสิ่งที่ผมใช้ คือ ตัว Camunda Connector ที่ช่วยให้เราสามารถ Config Web Service ได้ง่าย ไม่ต้องส่งงานให้ Delegate Code อย่าง BPMN Engine ของค่ายอื่นๆครับ สำหรับ

NOTE: สำหรับเรื่อง Service Task ตัว Spec ของ BPMN ไม่ได้ระบุใน Spec ชัดเจน ว่าต้องมีขั้นตอนการทำงานอย่างไร จึงเปิดให้ BPMN Engine แต่ละเจ้าสามารถเสริมเติมแต่ง Feature ได้เต็มที่ครับ

Camunda Connector

  • มี 3 รูปแบบ อ้างอิงจากเวอร์ชันที่ 7.9.0 ได้แก่
      • HTTP Connector – พวก REST API  ทั้งหลาย ใช้วิธี GET / POST และอื่นๆ แล้วเอา XML หรือ JSON มาใช้งานต่อ
    • SOAP Connector – พวก WSDL หรือ SOAP แบบเดิม
    • Custom – เขียน Code แล้วจัดการเองเลย

หลังจากเกริ่นนำได้ทดสอบ ตัว Connector แต่ละตัวกันแล้ว ตอนนี้มาดูตัวอย่างดีกว่าครับ โดยตัวอย่างที่ผมเขียนเป็นการใช้งาน HTTP Connector โดยใช้วิธี GET และผลลัพธ์ที่ได้ออกมาเป็นไฟล์ JSON ครับ เอาหละมาดูกันเลย ว่าเรา HTTP Connector แบบต้องใส่อะไรไปบ้าง

  • url => บอกว่าให้ไปเอาข้อมูลมาจาก Domain ไหน อะไร ถ้าเป็นแบบ GET ต้องยัด Parameter ลงไปในนี้ด้วยครับ
  • method => อันนี้กำหนดเป็น GET
  • header => บอกว่า Request ของเรามีอะไรบ้าง โดยกำหนดเป็น Key
    • key => Accept
    • value => application/json
  • payload => ไม่จำเป็นสำหรับ Method GET นะครับ ใส่เข้าไป จากการที่ลองไล่ Code ดูมันไม่ได้สนใจนะครับ

มาดูตัวอย่างกันบ้างดีกว่าครับ โดยผมทำเป็น Process ของการดึงข้อมูลของกระทู้ครับ

  • ข้อมูลจะถูก Mock มาจาก Open Source จาก https://jsonplaceholder.typicode.com/ อันนี้ผมเอาข้อมูล Mock จากตัว Web เลยครับ โดยใช้ URL https://jsonplaceholder.typicode.com/posts ซึ่งข้อมูลที่ได้มีผลลัพธ์ ดังนี้
  • Note: แต่เราสนใจเฉพาะ Id นะครับ ไม่ได้ ดึงมาหมด ดังนี้ URL อยู่ในรูป  https://jsonplaceholder.typicode.com/posts/<POST-ID>
  • ตัว BPMN Process – เดี๋ยวจะกล่าวในช่วงถัดไปครับ

มาเจาะลึกที่ BPMN Process ครับ ประกอบด้วย Task ย่อย 3 Task ครับ

  • Task “Enter Post Id” : เป็น User Task ให้ User กรอก Id ของ Post ที่ต้องการเรียกดูครับ
  • Task “Test REST-API (GET)” : สำหรับ Task นี้ เป็น Service Task ครับ โดย Task นี้เป็นพระเอกเลยครับ เพราะใช้เชื่อมกับ Web Service ครับ
    • กำหนด Config เป็น Connector
    • ภาพรวมของข้างในของ Connector
    • มาดูที่ส่วน Input ของตัว Connector ครับ
      • Connector-Id : ต้องเป็น http-connector เท่านั้น ห้ามตั้งชื่อเองนะครับ Engine ไม่รู้จัก
      • URL – สังเกตุว่า ผมไม่ได้ Map เป็น Text ครับ ผมใช้เป็น Script แทน เพราะต้องการเอา Post Id เช่น 1  จากตัวแปรของ Process ${PostId} มาใส่ต่อท้าย URL ตามคำสั่ง ดังนี้

        ภาพรวมของ URL
      • Method
      • Header
    • การจัดการ Output ครับ – ผลลัพธ์ของ Web Service อยู่ในรูปของ JSON ซึ่งผมจะเก็บไว้ใน postResult ครับ

      • แต่เนื่องจาก ผมต้องการเอาผลลัพธ์ที่เป็น JSON มายังลงใน Variable ของ Process ครับ เพื่อเอาไปแสดงผลใน Task ถัดไปครับ เลยต้องทำเป็น Script เพื่อกำหนดค่าครับ
  • Task “View Result” : เอาผลลัพธ์ที่ได้มาแสดงผลครับ โดยมีการ Config ดังนี้
  • BPMN Model สามารถดูได้จาก GitHub เลยครับ

ทดสอบครับ

  • Task “Enter Post Id” : ดึงข้อมูลของ Post Id 2
  • Task “Test REST-API (GET)” : หน้าที่ของ Engine ทำครับ เราต้องจัดการอะไร
  • Task “View Result” :

จบไปแล้วกับการงมๆ Web Service กับ BPMN ครับ โดยผมคิดว่าคงใช้ json-server ซึ่งเป็น Standalone JSON Mock REST-API มาใช้ทำ Thesis ครับ

 

[BPMN] ลองคิดตัวอย่างของ Completion Condition กัน

พอดีช่วงนี้ได้ลองเล่น BPMN แล้ว ปัญหาที่สำคัญของ Spec ตัว BPMN เอง คือ ตัวอย่างน้อย และไม่ครอบคลุมตามคุณสมบัติที่ได้ระบุไว้ใน Spec ครับ อย่างที่ผมโคตรงง ตอนนี้ คือ Attribute ของ Multi-Instance ของ Task ครับ ลองมาคิดตัวอย่างกันดีกว่าครับ

  • Task “Monitor Shipment” – Completion Condition คือ
    • สินค้าถึงจุดหมายปลายทางแล้ว
  • Task “Approval TOR” – Completion Condition คือ
    • คณะกรรมการ 2 ใน 3 ของทั้งหมดอนุมติ
  • Task “Process Transaction” – Completion Condition คือ
    • ยอดรวมของทุกสินค้า และบริการทั้งหมดต้องเกินจาก Budget ที่ตั้งไว้ หรือ ทุก Transaction สามารถประมวลผลได้ โดยไม่มีปัญหา
    • ** ถ้าเกินจาก Budget เข้า Flow การตัดสินใจของ User
    • ** ถ้าไม่เกินส่งต่อให้ Supplier จัดการ

เดี๋ยวคิดออกอีกแล้วมาเขียนเพิ่มครับ

[BPMN] มาลองใช้ Timer Start Event กันครับ

จาก Blog ตอนที่แล้ว หลังจากไปตบตีกับ Timer Start Event  ที่ไม่สามารถ Deploy ได้มา 5 เต็มๆ หลังจากแก้ปัญหาได้แล้ว คราวนี้มาลองดูตัวอย่างกันครับ หลายคนที่อ่าน Spec ของ BPMN เอาน่าจะงงกันครับ

มาดูกระบวนการแบบง่ายๆกันก่อนครับ

  • Note: กระบวนการที่ไม่ได้เป็นตัวอย่างของกระบวนการทางธุรกิจจริงๆนะครับ แค่เพียงทดสอบ Start Timer Event โดยมีส่วนประกอบ ดังนี้
  • Start Timer Event – จุดนี้พระเอกเลยครับ เพราะมีการกำหนดตาม Spec ของ BPMN ครับ ตาม Date Pattern   R4/2018-06-03T00:00/PT5M Task นี้จะถูก Execute ครั้งแรก ในวันที่ 2018-06-03 เวลาเที่ยงคืน และทำงานไปต่ออีก 4 ครั้ง และทิ้งช่วงครั้งละ 5 นาทีครับ
    • ถ้าดูใน XML ในอยู่ในส่วนของ Timer  <bpmn:timerEventDefinition> และ  <bpmn:timeCycle>  ซึ่งมีการกำหนดรูปแบบของวันที่ตาม ISO 8601 ครับ
    • การ Config ใน Camunda Modeler ตามรูปเลย
  • Script Task “Collect Order Data” – อันนี้ไม่มีอะไรมากครับ แต่ Print “Task Execute” ตามรูปครับ
  • User Task “Accept Data” – สำหรับ Task นี้จริงๆ ผมแค่อยากทดสอบว่า Task ถูก  Execute จริงไหม โดยให้ Task ถูก Assign ที่ user mary และต้องทำ Task ให้เสร็จ (property duedate)ภายใน  2018-07-30T12:00:00  ครับ โดยมี Config ตามรูป
  • End Event – จบการทำงานครับ

รอที่ Job ทำงานครับ

  • ต้องรอเวลา 2018-06-03 เวลาเที่ยงคืน ถ้าขี้เกียจก็เปลี่ยนเวลาเครื่องได้เลยครับ (ถ้าบน Windows ที่ยังไม่ Activate จะไม่สามารถย้อนเวลาได้ครับ)

ดูผลลัพธ์

  • ดูที Console ของ Tomcat ครับ มีการ Execute 5 ครั้ง ครั้งแรกตอน Task Start ครับ และอีก 4 ครั้งตาม Config ครับ (เสียดายที่ลืมเขียนเวลาครับ)
  • มาดูที่ Task ของ Mary ครับ  มีงาน 5 งานมารอให้ mary สะสางครับ
    • เวลา 00:00
    • เวลา 00:05
    • เวลา 00:10
    • เวลา 00:15
    • เวลา 00:20

จบไปแล้วกับ Blog ตอนนี้ครับ ต่อไปถ้าว่าง ผมคงลองเขียน Timer Start Event ตามกระบวนการธุรกิจจริงๆครับ ^__^

[BPMN] เมื่อ Timer Start Event ทำให้เกิดปัญหา duedate is null

หลังจากทำ Thesis มาเรื่อยๆ ผมได้มาลองใช้ Timer Start Event ของแบบจำลอง BPMN พอจะ Deploy เท่านั้นแหละ ?

พระเจ้า !!!! ทำไมทำร้ายเด็กน้อยอย่างฉันเช่นนี้

ผมติดปัญหานี้มาประมาณ 2 สัปดาห์ครับ

ระหว่างที่ทำก็ไล่ถาม Google ตรวจการกำหนด Config ไปเรื่อยๆ จนถึงเวลาแล้วทีผม ต้องเอา Stacktrace มาลองไล่ Code ของตัว BPMN Engine ใน GitHub ครับ ซึ่งพอไล่ๆไปแล้ว

  • abstract class JobDeclaration ผมสงสัย Method resolveDueDate เพราะ มัน Code ที่น่าสงสัยครับ Return null เฉย
  • หลังจากขุดไปเรื่อยๆ เจอ Ticket อันนึงครับ อันนี้ >> https://app.camunda.com/jira/browse/CAM-4135 โดยสิ่งที่ผมสงสัย คือ ตัว XML Config ครับ

พบสาเหตุแล้ว

  • หลังจากไล่ Code มานานเลย ผมสังเกตุว่าเวลาที่กำหนดในแบบจำลอง มันเป็นเวลาในอดีตครับ 2018-04-30 แต่ในเวลาปัจจุบัน คือ 2018-06-05 และพอไล่ไปดู Code อีก ซับซ้อนมากครับ แต่ใจความสำคัญ คือ ว่าวันที่กำหนดใน Timer Start Event เป็นวันที่ในอดีต เมื่อเทียบกับวันที่ของ BPMN Engine แล้ว มันจะไปกำหนดค่า  jobExecutorAcquireByDueDate  ที่อยู่ใน Class  ProcessEngineConfiguration ให้มีค่าเป็น false ครับ
  • อ๋อ สรุปว่า Config XML ที่เจอ อาจจะยังไม่จำเป็นต้องใช้ [ผมของไปขุดเพิ่มเติมก่อน] แต่ตอนนี้ที่รู้แน่ๆ คือ ถ้า Code ถ้ามันตีความได้ว่า วันที่เราส่งไปในรูปแบบ ISO 8601 แล้วพบว่าเป็นวันในอดีต ระบบมัน Set Duedate เป็น null แทน
    • ถ้าในเครื่องจริง อาจจะต้องย้อนเวลาของ OS เอาครับ
    • แต่ถ้าทำพวก Unit Test สามารถใช้ตัว  ClockUtil  ได้ครับ โดยจะเอาไว้ในส่วนของ @Before หรือ @BeforeClass ของ JUnit4 ก็ได้ครับ ตาม Code ตัวอย่าง ดังนี้

มาลองดูผลลัพธ์กันครับ

  • สามารถทำงานได้แล้วครับ ^___^

[BPMN] เพิ่มเติมเกี่ยวกับ multiInstanceLoopCharacteristics

จาก Blog ที่แล้วที่ผมได้เขียนเกี่ยวกับตัวอย่างของ multiInstanceLoopCharacteristics โดยใช้ตัวอย่างเรื่อง กระบวนการของการขอเสนอรางวัลให้กับพนักงานดีเด่น ซึ่งลองเล่นไป เล่นมาแล้วพบปัญหา ดังนี้

  • Task “Evaluate Award” ได้ถูก Assign ให้เป็น Group โดยที่กรรมการแต่ละท่านเลือกไปทำครับ แต่มันสามารถ Claim ซ้ำกันได้ครับ แบบนี้ไม่ดีแน่ครับ
  • ทางแก้ไขหล่ะ
    • แบบที่ 1: แก้ไข Object ของ MultiInstance แล้วให้กำหนด User เป็น Assignee สำหรับ Task นั้นเลย
    • แบบที่ 2:แก้ไขโดยการเพิ่ม Listener แล้วเขียน Code ขึ้นมาตรวจสอบครับ
  • ** สำหรับใน Blog นี้ ผมใช้วิธีแรกครับ แต่จะแทรก ตัวอย่างของ Listener เข้าไปด้วยครับ

ลุยกันเลยครับ

  • สำหรับภาพรวมของกระบวนการ (Process) เหมือนเดิมครับ แต่จะแก้ Coding และ Config ข้างในมากกว่าครับ
  • มาเริ่มกันเลยครับ
  • ใน Script Task “Setup Reviews” ผมแก้จากการใช้ List มาเป็น Dictionary ครับ โดยให้ key = ชื่อคณะกรรมการ และ value = ผลการประเมินครับ ตาม Code ตัวอย่างเลย
  • มาที่พระเอกของแรกแล้วครับ ตรง Sub-Process “EvaluateProcess” ที่ถูกกำหนดเป็น MultiInstance ครับ
    • แก้ไข MultiInstance ครับ
      • มาดูที่รูปก่อนครับ
      • แล้วที่นี้กำหนดข้อมูลของแต่ะส่วน ดังนี้ครับ
        • Loop Cadinalityอันนี้เหมือนเดิมครับ คือ เอาค่าจากตัวแปร ${RequiredNumOfPeers} ที่กำหนดมาจาก Task Associate Reviews 
        • Collection – Data ที่ใช้ใน multiInstanceLoopCharacteristics ครับ โดยช้อมูลชุดนี้เกิดจาก Task Setup Reviews ที่สร้าง MAP ชื่อ ${reviewResultMap} ที่มีขนาดเท่ากับ ${RequiredNumOfPeers} ถ้าในตัวอย่างเท่ากับ 3 ซึ่งในแต่ละ Instance ของ Task เห็นข้อมูล reviewsResult(Object แต่ละอันใน MAP reviewsResults โดยดึงมาเฉพาะ Key ถ้าดูในแบบจำลองในส่วน Collection กำหนดให้ค่าเท่ากับ  ${reviewResultMap.keySet()}  ) ซึ่งประกาศไว้ในส่วน  element ในรูปแบบ 1 Instance ต่อ 1 Object ครับ
        • completionCondition ครับ ซึ่งถ้าเงื่อนไขเป็นจริง ก็จะออกจาก  multiInstanceLoopCharacteristics ครับ โดยเงื่อนไขทาง Business คือ กรรมการ 2 ใน 3 ท่าน ได้เข้าร่วมการประเมินครับ ซื่งสามารถกำหนดเงื่อนไขได้ ดังนี้
    • เพิ่ม Listener เพื่อกำหนดตัวแปรระดับ Local ให้ Engine รู้จักครับ โดยผมเพิ่มตัวแปร reviewer(ชื่อผู้ประเมิน) และ reviewResult(ผลการประเมิน) ซื้อยู่ใน Scope ของ Sub-Process “EvaluateProcess” ดังนี้ครับ
      • มาดูที่รูปก่อนครับ
      • ในส่วนของ Script มีการแก้ไข โดยจะ Execute ต่อเมื่อมีการเรียกใช้ Sub Process “EvaluateProcess” ครับ โดยมีรายละเอียดของ Script ดังนี้
  • Note: อย่าลืมแก้ไขชื่อตัวแปรให้ครับนะครับ ถ้าไป Run ที่ตัว BPMN Engine แล้วเสียเวลาพอสมควรครับ

ทดสอบกันเลยครับ

  • Mary ได้เริ่มการทำงานของ Reward Process แล้วครับ
  • Mary กรอกข้อมูลเพื่อเสนอชื่อของผมไปครับ (ในชีวิตจริงๆ ก็อยากได้เงินก้อนแบบนี้บ้าง T__T)
  • กำหนดรายละเอียดของ Task Associate Reviews  ครับ
  • สังเกตุดีๆว่าตอนนี้ Task “Evaluate Award” ได้ถูก Assign เข้าไปที่คณะกรรมการแต่ละท่านแล้วครับ เมื่อ Mary ได้เขียน Flow มาจนถึง Sub Process “EvaluateProcess” พบว่า User ที่เป็นกรรมการทั้ง 3 ท่านได้ถูก Assign Task เรียบร้อยครับ
    • User jame
    • User john
    • User peter
  • และเมื่อ 2 ใน 3 ของคณะกรรมการได้พิจารณา Task เรียบร้อยแล้ว พบ่วาระบบทำการ Clear อีก 1 Instance ให้อัตโนมัติครับ
  • เมื่อจบการตัดสินของคณะกรรมการแล้ง ระบบตัดสินผลลัพธ์ และแจ้งให้ Mary รับทราบผลลัพธ์ครับ

สำหรับ Source Code ของแบบจำลองครับ

  • มาดูที่ Github ได้เลยครับ

[BPMN] ตัวอย่าง multiInstanceLoopCharacteristics

หลังจากโดนมรสุมงานไปจนวันหยุดเดือนเมษา หายวับไปกับรายงานแบงค์ชาติ DataSet เดือนนี้ ผมเริ่มมีเวลาว่างแล้วครับ โดยจาก Blog ตอนก่อนที่เขียนเกี่ยวกับ BPMN ไปในเรื่องของ Loop หรือ การทำซ้ำ ที่จะเน้นไปในตัวของ StandardLoopCharacteristics สำหรับใน Blog ตอนนี้เป็นตัวอย่างของ multiInstanceLoopCharacteristics ครับ

แล้วความแตกต่างระหว่าง StandardLoopCharacteristics  กับ multiInstanceLoopCharacteristics  ครับ

  • StandardLoopCharacteristics – ใช้มองเหมือน for-loop ทั่วไปครับ โดยที่ Activity หรือ Task มีเพียง 1 Instance เท่านั้นครับ
  • multiInstanceLoopCharacteristics – เป็น Loop เหมือนกันครับ แต่ทำงานในลักษณะของขนานกันครับ มีหลาย Instance ทำงานพร้อมๆกันครับ โดยถ้าในมุมของโปรแกรมมิ่ง มันเป็นเรื่องของการแตก Thread จัดการกับพวก Concurrent ครับ ถ้าใน C# ให้นึกถึง Parallel.ForEach ครับ

มาดูตัวอย่างของ multiInstanceLoopCharacteristics กันดีกว่า

  • อ่านผ่านๆมา หลายคนน่าจะงงครับ คราวนี้ลองมาดูตัวอย่างกันครับ โดยกระบวนการตัวอย่างที่ผมเขียนใน Blog เป็นกระบวนการของการขอเสนอรางวัลให้กับพนักงานดีเด่นครับ โดยผู้จัดการ(Manager) User Mary ต้องเสนอชื่อ เพื่อให้คณะกรรมการ(Reward Commitee) ซึ่งประกอบไปด้วย User Jame, Peter และ John ทำการตรวจสอบ และอนุมัติ ดังรูป
  • โดยกระบวนการมีขั้นตอน ดังนี้ครับ
    • Task “Enter Employee who shall receive Reward” – เป็นการใส่ข้อมูลของพนักงานที่ควรได้รับรางวัล ได้แก่ ข้อมูลพนักงาน และผลรวมที่ผ่านมารวมทั้งเงินรางวัลที่ต้องการมอบครับ
    • Task “Associate Reviews” – ส่งข้อมูลต่อ เพื่อจัดการประชุมครับ โดยมีเงื่อนไขที่จำเป็น ดังนี้

      • Field “RequiredNumOfPeers” – จำนวนคณะกรรมการทั้งหมด ใน BPMN หมายถึงค่า  loopCardinality ที่ใช้กำหนดจำนวน Instance สูงสุดของ Task นั้นๆ
      • Field “RequiredMinNumofPeer” – จำนวนคณะกรรมการขั้นต่ำที่ต้องเข้าร่วมการตัดสินใจ
      • Field “RequiredNumOfApproval” – ผลการประชุมเท่าไหร่ จึงจะถึงว่าคำร้องของมอบรางวัลถึงจะได้รับการอนุมัติ
      • ตัวอย่างจากแบบจำลองได้กำหนดไว้ว่า ต้องมีคณะกรรมการ 3 คน โดยต้องมีอย่างน้อย 2 คนเข้าร่วมตัดสินใจ ซึ่งผลการอนุมัติต้องมีอย่างน้อย 2 คนทำการอนุมัติ
    • Task “Setup Reviews” – ถ้าเป็นงานสมัยก่อนเตรียมเอกสาร และแบบฟอร์มการอนุมัติครับ แต่นี่เป็น BPMN แล้ว ให้ระบบจัดการเอาครับ โดยผมได้ใช้ List แทนใบอนุมัติของกรรมการทั้ง 3 ท่านครับ
    • Sub-Process “Evaluate Process” – เป็น Sub Process ครับ ซึ่งเป็น  multiInstanceLoopCharacteristics โดยกิจกรรมนี้ จะสิ้นสุดเมื่อมีกรรมการ 2 ใน 3 ท่านเข้าร่วมครับ โดยในแบบจำลองมีการตั้งค่า ดังนี้ครับ

        • Loop Cadinality – เอาค่าจากตัวแปร ${RequiredNumOfPeers} ที่กำหนดมาจาก Task Associate Reviews
        • Collection – Data ที่ใช้ใน multiInstanceLoopCharacteristics ครับ โดยช้อมูลชุดนี้เกิดจาก Task Setup Reviews ที่สร้าง List ชื่อ ${reviewsResults} ที่มีขนาดเท่ากับ ${RequiredNumOfPeers} ถ้าในตัวอย่างเท่ากับ 3 ซึ่งในแต่ละ Instance ของ Task เห็นตัวแปร reviewsResult(Object แต่ละอันใน List reviewsResults) ซึ่งประกาศไว้ในส่วน   element ในรูปแบบ 1 Instance ต่อ 1 Object ครับ
        • completionCondition ครับ ซึ่งถ้าเงื่อนไขเป็นจริง ก็จะออกจาก  multiInstanceLoopCharacteristics ครับ โดยเงื่อนไขทาง Business คือ กรรมการ 2 ใน 3 ท่าน ได้เข้าร่วมการประเมินครับ ซื่งสามารถกำหนดเงื่อนไขได้ ดังนี้
    • กลับมาดูที่กิจกรรมย่อยๆ ภายใน Sub-Process “Evaluate Process”
      • Task “Evaluate Award” – งานในส่วนนี้เป็นของ RewardCommittee (กำหนดเป็น Group ไว้ในตัว BPMN Engine) ที่เข้ามาเลือก Task และรับงานไปทำต่อ (Claim Task) ซึ่งในงานของกรรมการแต่ละท่าน คือ ตรวจสอบข้อมูล และทำการอนุมัติครับ
      • Task “Update Result” – บันทึกผมการอนุมัติเข้าระบบครับ
      • Note: เมื่อ Execute Process มาจนถึง Step “Evaluate Process” สิ่งที่ระบบทำ คือ สร้าง Instance ขึ้นมา 3 Instance ครับ เพื่อให้คณะกรรมการ 3 ท่าน เข้ามาพิจารณารับงานไปทำต่อ (Claim Task) ครับ
    • Task “Calculate results” – นำผลลัพธ์ของกรรมการทุกท่าน มาคำนวณคะแนนสุดท้ายครับ นำคะแนนที่ได้ไปผ่านเงื่อนไขตาม Sequence Flow ครับ
    • Excustive Gateway “Is Approved Award” – ตรวจผลการอนุมัติ โดยเงื่อนไขอยู่ใน conditionExpression ของ Sequence Flow ครับ
      • Task “Note Personnel File Approved” – อนุมัติ
      • Task “Note Personnel File Rejected” – ไม่อนุมัติ
    • อ่านมานานแล้วมาดู Source Code ใน GitHub ดีกว่าครับ

[BPMN] สรุป Step การพัฒนา BPMN Application ด้วย Camunda BPMN Engine

หลังจากได้ลอง BPMN Engine ตัว Activiti ไป ช่วงมกราคม และลองตัว jBPM ไป แต่ไม่ค่อย Work เท่าไหร่ คราวนี้มาถึงคิวของ Camunda  บ้างแล้วครับ

Camunda BPMN Engine คือ อะไร

  • เป็น BPMN Engine ที่แตกสาย (Fork มาจาก Project ของ Activiti เพื่อเน้นการพัฒนาส่วนของ Engine เอาไปใช้พัฒนา Application ได้ง่ายขึ้น และเพิ่มมาตรฐานใหม่อย่าง DMN และ CMMN ทางที่ OMG (Object Management Group) ได้ประกาศขึ้นมา และนำมาใช้เพื่อลดความซับซ้อนของ BPMN ครับ

ขั้นตอนการพัฒนา BPMN Application บน Camunda

  • สร้างแบบจำลอง BPMN ก่อนครับ โดยทาง Camunda ได้เตรียมตัว Camunda Modeler ไว้ให้ครับ
  • ลงมือทำแบบจำลองครับ อันนี้เป็นแบบจำลองของ https://fundamentals-of-bpm.org ที่ถูกอ้างอิงใน Paper หลายๆอันครับ
  • นำแบบจำลองมาสร้างเป็นเว็บแอปพลิเคชันต่อครับ โดยผมใช้ Eclipse เพื่อบิ้วไฟล์ .war สำหรับไป Deploy ครับ
    • ถ้าใครไม่รู้โครงสร้างของ Project ไม่เป็นได้ครับ ใช้ Maven Project Templates (Archetypes) ได้เลยครับ
    • จากนั้นวางไฟล์ .BPMN ไว้ที่ Folder Resource ครับ
    • ถ้ามีทำ Custom UI ก็วางไฟล์ UI ไว้ใน Folder WebApp ครับ
  • จากนั้นใช้คำสั่ง  maven -install  เพื่อบิ้วตัว .war ขึ้นมาครับ

ติดตั้งแบบจำลอง

  • download Camunda BPMN Engine มาจากนั้นแตกไฟล์ Zip start-camunda.bat จากนั้นเรียกไฟล์ (Windows) เพื่อ Start Server ซึ่งเมื่อ Start เรียบร้อยแล้ว มันพาไปหน้าจอ Welcome ซึ่งมี 3 Module หลังที่ต้องสนใจครับ
    • Cockpit – เอาไว้ Monitoring จัดการกับ Process
    • Task – เอาไว้สำหรับให้ User แต่ละ Role เข้ามาใช้งาน เพื่อเดินกระบวนการ ทางหน้าที่ของแต่ละ User
    • Admin – เอาไว้จัดการสิทธิ์ทั้งหลาย
  • ถ้าเข้ามาใน Cockpit ด้วย username  demo  password  demo  พบว่ามี sample process deploy รอไว้แล้วครับ ต่่อไปเรา Deploy Process อันใหม่ที่ทำ เพิ่มครับ
  • นำไฟล์ .war ที่ได้ เข้าไปวางในโพลเดอร์  <<SERVER-PATH>>\camunda-bpm-enigne\server\apache-tomcat-x.x.xx\webapps จากนั้นรอตัว Tomcat มัน Deploy Process ครับ โดยมีข้อความแจ้งผล ดังรูป
  • ลองไปดูใน Cockpit มี Process ที่ Deploy ทั้งหมด 3 ตัวครับ

ทดสอบใช้งานครับ

  • Start Process ให้ทำงานก่อนครับ โดยเข้าไปที่ Camunda-Task จากนั้น Start Process
  • เลือก Process ที่ได้เพิ่ง Deploy ไปเลยครับ
  • ระบบขึ้น Form ให้กรอก ดังรูป
  • สำหรับการทดสอบมี 6 กรณีทดสอบ
    • กรณี Happy Flow
    • กรณี ผู้ใช้กรอกข้อมูลไม่ครบ จนกลับมาที่ Task “Update Loan Application”
    • กรณี เจ้าหน้าที่ฝ่ายสินเชื่อ(Loan Officer) ตรวจที่ Task “Assess eligibility” แล้วคุณสมบัติไม่ตรง
    • กรณี ผู้ใช้กรอกข้อมูลไม่ครบ จนกลับมาที่ Task “Update Loan Application” แล้วค้างที่ Task นั้น 5 วัน ระบบต้อง Reject ทิ้ง
    • กรณี เจ้าหน้าที่ฝ่ายสินเชื่อ(Loan Officer) ตรวจที่ Task “Verify repayment agreement” แล้วค้างที่ Task นั้น 14 วัน ระบบต้อง Reject ทิ้ง

Note

  • ถ้าใช้ Form ของ Camunda ระวังพวก Date Type “Date” ที่ต้องเป็น ISO 8601 ไม่งั้นมัน Render Form ไม่ขึ้น

Reference

[BPMN] Loop หรือ การทำซ้ำ

แม้ว่าตัว BPMN ถูกออกแบบมาสำหรับทางฝั่ง Business แต่มีการทำบางอย่าง ที่ยังต้องใช้มีการทำวนซ้ำ หรือ ถ้าในภาษา Technical ของ Developer ทั้งหลาย ว่าวนลูป (Loop) ครับ สำหรับใน BPMN สามารถเขียนได้ 2 แบบครับ ได้แก่

  • Loop Activity
  • Non-Loop Activity

Loop Activity

โดย Loop Activity คือ Loop ที่เกิดกำหนด Property ของตัว Activity ครับ ถึงถ้าไปดูใน Spec ของ BPMN อยู่ในรูปแบบของ XML Tag StandardLoopCharacteristics

มาลองดูตัวอย่างกันครับ ภาพด้านล่าง ผมเอามาจาก Tools Visual Paradigm Modeler ครับ เป็น

  • สัญลักษณ์ลูกศรวน บนตัว Activity
  • การกำหนด Attribute ใน XML Tag StandardLoopCharacteristics โดยอยู่ในส่วนของ Standard Loop Specification

Note: แต่ Loop Activity BPMN-Engine ที่เป็น Open-Source ณ ปี 2018 ทั้งหมด ยังไม่ Support ครับ

Non-Loop Activity

ส่วน Non-Loop Activity นั้น มองภาพที่ใหญ่ขึ้นจาก Activity เดี๋ยวๆ โดยการสร้าง Loop จากการใช้ Exclusive Gateway นำมาประกอบกันครับ มาลองดูตัวอย่างกันครับ

  • อย่าง Loop ที่ถ้าใช้ Loop Activity testBefore=true สามารถปรับเป็น Exclusive Gateway ได้ตาม Pattern ดังนี้ครับ
  • อย่าง Loop ที่ถ้าใช้ Loop Activity testBefore=false สามารถปรับเป็น Exclusive Gateway ได้ตาม Pattern ดังนี้ครับ

หมายเหตุ

  • คำอธิบายนี้อิงตาม Spec ของ BPMN 2.0 ที่ทาง OMG ได้ประกาศไว้ครับ
  • ถ้าไปดูตัว BPMN-Engine อาจจะยังทำไม่ครบตาม Spec ของ OMG อันนี้ผมเข้าใจว่า เพราะมันมี Non-Loop Activity ที่สามารถทำงานทดแทนได้อยู่แล้วครับ

[BPMN] ลองใช้ Process ที่ได้เพิ่งสร้างกัน

จาก Blog ตอนก่อนหน้าที่เราได้ทำอะไรไปหลายๆอย่าง ทั้ง

มาใน Blog ตอนนี้ เรามาใช้ ลองเป็น End-User ของ Process ที่ทำครับ โดยหลังจาก Deploy Process เราต้องเข้าในส่วนของ Activiti Task กันครับ มาทวนภาพรวม Process กันก่อนครับ ดังรูป

เริ่่มลองใช้งาน Process โดยต้อง Login เป็น User ที่อยู่ใน Group Employee ครับ

สวมบทบาทเป็น Employee  กันครับ

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Employee ครับ
  • เข้ามาที่ เลือก Task App ครับ
  • มา Start Procrss ที่ Deploy ไว้กันเลย
  • เจอ Process ที่สร้างไว้แล้ว เลือกเลยครับ
  • ตรงนี้ เราเห็นแล้วว่า Active Process ขึ้นมาแล้วครับ

    • ถ้ากด Show Diagram เห็นว่า Task นี้ ยังอยู่ที่ Employee Request Budget ครับ
  • ถ้าต้องการทำ Task ใน Process นั้น ให้ Double Click ที่ Active ซึ่งถ้าต้องการทำ Process ต่อก็สามารถกด Claim ได้เลยครับ
  • จากนั้นกรอกข้อมูลที่จำเป็นลงไปครับ
  • พอกลับมาดูที่ Process ตอนนี้ Active Task อยู่ที่ Manager แล้วครับ

    • ถ้ากด Show Diagram เห็นว่า Task นี้ ยังอยู่ที่ Manager Review / Approve ครับ เพราะ วงเงินที่ขอไว้เกินกำหนด 1,000 บาท
  • สังเกตุดีๆครับ ตอนนี้ Assigned to nobody ครับ ให้เพิ่มคนที่อยู่ในกลุ่ม Manager ดังนี้
    • เลือก Involve someone else and start collaborating
    • จากนั้นเลือก User ในกลุ่ม Manager ครับ

Manager เข้ามา Claim Task ว่าจะอนุมัติ หรือไม่ ?

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Manager ครับ
  • พอเข้ามาที่ Task App จะเจอว่ามี TaskManager Review / Approve รออยู่ครับ
  • Manager Claim Task นั้นไปครับ
  • ปรากฏว่า Manager ไม่อนุมัติ (แล้วจะทำอย่างไรต่อ !!!)
  • ตอนนี้ Process เลย วนกลับไปที่ Employee ให้ใส่ข้อมูลวงเงินมาใหม่

เมื่อ Employee แก้ข้อมูลใหม่ แล้วส่งงานกลับมาให้ Manager

  • ตอนนี้ ถ้าสังเกตุ Complete Task หลังจาก Employee ใส่ข้อมูลมาใหม่แล้ว
  • หลังจาก Manager อนุมัติแล้ว งานส่งต่อไปให้กับฝ่ายบัญชี-การเงินครับ

เมื่อฝ่ายบัญชีจัดการเสร็จแล้ว จบกระบวนการ

  • Login เข้าระบบด้วย User ที่อยู่ใน Group Accountant ครับ
  • พอมาดูที่ Task Manager ส่งงานมาให้แล้วครับ (เพราะ วงเงินที่ขออนุมัติแล้ว)
  • จากนั้น Claim Task
  • แต่เนื้องจาก Task นี้เป็น Task สุดท้ายแล้ว และก็ไม่มีิ Process อะไร นักบัญชีเลยกด Complete Task ไปครับ

จบไปแล้วกับ Blog เรื่องยาวครับ แม้ว่า Process ที่ทำเป็น Demo อาจจะไม่สมจริงเท่าไหร่นะครับ หากทุกท่านอ่านแล้วสงสัยอะไร สามารถทักมาได้ หรือทวงติงกรณีที่ผมเขียนผิดครับ ^__^