Cross-Workflow System Behavior (Implemented)
Dokumen ini menjelaskan behavior runtime apps/worker-workflow/src/cross-workflow sesuai implementasi saat ini.
Komponen utama:
apps/worker-workflow/src/cross-workflow/services/cross-workflow.consumer.tsapps/worker-workflow/src/cross-workflow/services/cross-workflow.service.tsapps/worker-workflow/src/cross-workflow/contracts/cross-workflow.contract.tsapps/worker-workflow/src/cross-workflow/utils/relation-type.util.ts
1. Source Event dan Kontrak Trigger
Source trigger cross-workflow:
- CDC
pgcdc.public.wxl_submission_log - Consumer memakai
@JetStreamConsumer(...)+@MessageHandler() - Bootstrap/subscribe dijalankan
JetStreamConsumerRegistryService(bukan di consumer)
Payload internal yang dikirim consumer ke service (CrossWorkflowTriggerPayload):
submissionIdactionIdfromStatusIdtoStatusIdactorUserIdsourceLogIdsourceLsnchangedAtsourceTable = 'wxl_submission_log'
2. Filter CDC di Consumer (Kapan Event Diproses)
Consumer hanya memproses event yang memenuhi semua syarat ini:
- JSON valid
payload.source.table === 'wxl_submission_log'payload.op === 'c'(insert log saja)after.submission_idadaafter.action_idada
Jika salah satu tidak terpenuhi:
- event di-
ack - service tidak dipanggil
3. Mapping CDC -> Trigger Payload
Behavior mapping di consumer:
actorUserIdfallback:actor_user_id -> user_updated -> user_createdchangedAtfallback:after.date_updated(jika valid)after.date_created(jika valid)payload.ts_msDate.now()
sourceLsnhanya diisi jika numeric valid
Semua field string dinormalisasi (trim) dan kosong dianggap null.
4. Flow Utama CrossWorkflowService.execute(...)
Semua eksekusi berjalan dalam transaksi DB (QueryRunner).
Urutan flow:
- Start transaction.
- Cek apakah trigger benar-benar perubahan status (
toStatusIdada dan berbeda darifromStatusId). - Resolve
SubmissionServiceV2viaModuleRef+ContextIdFactorydengan actor request context. - Lock source submission (
pessimistic_read). - Ambil konfigurasi
WmlCrossWfConnberdasarkansourceActionId. - Iterasi tiap connection dan tentukan relation type (
ONE_TO_MANY/MANY_TO_ONE/UNKNOWN). - Untuk
MANY_TO_ONE, jalankan readiness check dulu. - Resolve target submissions.
- Dedupe per
targetSubmissionId + targetActionId. - Trigger
SubmissionServiceV2.setSubmission(...)pada target. - Commit transaction.
Jika error:
- rollback transaction
- error dilempar ulang (consumer akan
nak)
5. Guard / Early Return (Skip Dengan Aman)
Service akan commit + return tanpa trigger target jika:
- transition tidak mengubah status (
toStatusIdnull ataufromStatusId === toStatusId) - source submission tidak ditemukan
- tidak ada koneksi
WmlCrossWfConnuntuksourceActionId
Consumer akan ack (bukan retry) jika:
- payload malformed
- event tidak relevan untuk cross-workflow
6. Relation Type Behavior
6.1 ONE_TO_MANY
- Tidak perlu readiness check.
- Langsung resolve target submissions lalu trigger target action.
6.2 MANY_TO_ONE
- Wajib lulus
isManyToOneReady(...)sebelum trigger target. - Jika belum ready:
- skip connection (bukan error)
- transaksi tetap commit normal
6.3 UNKNOWN
- Tidak ada branch khusus.
- Flow tetap lanjut seperti relation biasa (tanpa readiness gate
MANY_TO_ONE).
7. Target Resolution Behavior (resolveTargetSubmissions)
Dasar filter target:
workflowId = conn.targetWorkflowId- optional
entity = conn.targetEntity
Penentuan entityId target:
- Coba mapping field (
sourceEntity/sourceField -> targetEntity/targetField) - Jika mapping menghasilkan banyak id, gunakan
In([...]) - Jika mapping kosong, fallback ke
sourceSubmission.entityId(backward compatibility)
Query target submission memakai lock:
pessimistic_write
8. Field Mapping Behavior dan Safety
Fitur field mapping dipakai untuk relasi lintas entity (mis. parent-child by field value).
Behavior:
- Ambil nilai field dari entity source (
loadEntityFieldValue) - Cari row entity target dengan nilai field yang sama
- Ambil
identity target, lalu cari submission target berdasarkanentityId
Safety guard:
- nama tabel/field divalidasi regex identifier aman (
isSafeIdentifier) - jika identifier tidak valid:
- skip mapping
- log warning
9. MANY_TO_ONE Readiness Check (Milestone Aggregation)
Tujuan:
- memastikan semua sibling source yang terkait sudah melewati action milestone sebelum trigger target.
Ringkas flow isManyToOneReady(...):
- Validasi config minimum (
sourceEntity,sourceField,sourceWorkflowId,sourceActionId) - Ambil nilai grouping dari source entity (mis.
parent_id) - Cari semua entity source sibling dengan nilai grouping yang sama
- Cari semua submission source untuk sibling tersebut (
workflowId + entity + entityId IN (...)) - Query
wxl_submission_loguntuk mendeteksi submission yang sudah menjalankansourceActionIdto_status_id IS NOT NULLfrom_status_id IS DISTINCT FROM to_status_id
- Ready jika semua submission source sibling sudah ada di set completed
Jika config tidak valid / identifier tidak aman / data tidak lengkap:
- return
false(skip trigger)
10. Dedupe dan Idempotency Scope
Dedupe yang aktif saat ini:
Setin-memory per transaksi eksekusi- key:
${targetSubmissionId}:${targetActionId}
Tujuan:
- mencegah duplicate trigger dalam satu event ketika beberapa connection menghasilkan target yang sama
Catatan:
- Ini bukan dedupe lintas event global
- Redelivery CDC tetap bisa memicu eksekusi ulang (bergantung downstream behavior
SubmissionServiceV2)
11. Side Effect ke Target Workflow
Eksekusi target dilakukan via:
SubmissionServiceV2.setSubmission(...)
Payload target yang dikirim:
submission_idworkflow_idaction_idactor_idactor_user_idoverride = truesource = 'CROSS_WORKFLOW'do_not_clear_cache = true
12. Error Handling dan Retry
12.1 Consumer
- Malformed / irrelevant event ->
ack - Error saat
service.execute(...)->nak(8000)
12.2 Service
- Error query/trigger target -> rollback transaction lalu throw
13. Test-Covered Behaviors (Saat Ini)
Consumer spec sudah cover:
- malformed JSON ->
ack - table non-
wxl_submission_log->ack - non-create op ->
ack - missing
submission_id/action_id->ack - valid CDC ->
service.execute(...)+ack - actor fallback mapping
changedAtfallback kets_ms- service error ->
nak(8000)
Service spec sudah cover:
- early return non-status-change
- source submission not found
- no connection config
ONE_TO_MANYtrigger- dedupe target
MANY_TO_ONEreadiness false/true- actor default
system - rollback on downstream error
- skip invalid target config
MANY_TO_ONEreadiness sibling milestone check
14. Batasan Implementasi Saat Ini
- Consumer hanya listen
op='c'(wxl_submission_loginsert); update log tidak diproses. - Dedupe masih per-event/per-transaction, bukan lintas redelivery global.
UNKNOWNrelation type tidak punya guard khusus (hanya lewat flow umum).- Behavior observability/logging masih plain logger per service (belum structured tracing).