diff --git a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.plantuml b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.plantuml index 478074f80..3f29d4657 100644 --- a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.plantuml +++ b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.plantuml @@ -103,6 +103,61 @@ group Transfer Expiry ||| TOPIC_NOTIFICATIONS <- NOTIFY_HANDLER: Consume message ref over DFSP1, TOPIC_NOTIFICATIONS : Send notification to Participant (Payer)\n + alt Timeout before any processing + note left of NOTIFY_HANDLER #yellow + PUT /bulkTransfers/ + { + headers: , + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + ] + } + } + end note + else Timeout in middle of processing + note left of NOTIFY_HANDLER #yellow + PUT /bulkTransfers/ + { + headers: , + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "transferId": , + "fulfilment": + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + ] + } + } + end note + end NOTIFY_HANDLER -> DFSP1: Send callback notification end ||| @@ -110,6 +165,61 @@ group Transfer Expiry ||| TOPIC_NOTIFICATIONS <- NOTIFY_HANDLER: Consume message ref over DFSP2, TOPIC_NOTIFICATIONS : Send notification to Participant (Payee)\n + alt Timeout before any processing + note left of NOTIFY_HANDLER #yellow + PUT /bulkTransfers/ + { + headers: , + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + ] + } + } + end note + else Timeout in middle of processing + note left of NOTIFY_HANDLER #yellow + PUT /bulkTransfers/ + { + headers: , + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "transferId": , + "fulfilment": + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": + } + "transferId": + }, + ] + } + } + end note + end NOTIFY_HANDLER -> DFSP2: Send callback notification end end diff --git a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg index 20faf4b81..b6ec04627 100644 --- a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg +++ b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg @@ -1,406 +1,361 @@ - + + - - - - - + + + + + - - 3.1.0. Transfer Timeout (incl. Bulk Transfer) - - - - Financial Service Providers - - - - ML API Adapter Service - - - - Central Service - - - - - - - - - - - - DFSP1 - - - Payer - - - - - DFSP1 - - - Payer - - - - - DFSP2 - - - Payee - - - - - DFSP2 - - - Payee - - - - - ML API - - - Adapter - - - - - ML API - - - Adapter - - - - - ML API Notification - - - Event Handler - - - - - ML API Notification - - - Event Handler - - - - - Transfer Timeout - - - Handler - - - - - Transfer Timeout - - - Handler - - - - - - - topic- - - - transfer-position - - - - - topic- - - - transfer-position - - - - - topic-event - - - - - topic-event - - - Position Event - - - Handler - - - - - Position Event - - - Handler - - - - - - - topic- - - - notification - - - - - topic- - - - notification - - - Bulk Processing - - - Handler - - - - - Bulk Processing - - - Handler - - - - - - - topic- - - - bulk-processing - - - - - topic- - - - bulk-processing - - - - - - Transfer Expiry - - - - - ref - - - Timeout Handler Consume - - - - - alt - - - [transferStateId == 'RECEIVED_PREPARE'] - - - - - alt - - - [Regular Transfer] - - - - - 1 - - - Produce message - - - - [Individual Transfer from a Bulk] - - - - - 2 - - - Produce message - - - - [transferStateId == 'RESERVED'] - - - - - 3 - - - Produce message - - - - - 4 - - - Consume message - - - - - ref - - - Position Hander Consume (Timeout) - - - - - alt - - - [Regular Transfer] - - - - - 5 - - - Produce message - - - - [Individual Transfer from a Bulk] - - - - - 6 - - - Produce message - - - - - opt - - - [action IN ['bulk-timeout-received', 'bulk-timeout-reserved']] - - - - - 7 - - - Consume message - - - - - ref - - - Bulk Processing Consume - - - - - 8 - - - Produce message - - - - - opt - - - [action IN ['timeout-received', 'timeout-reserved', 'bulk-timeout-received', 'bulk-timeout-reserved']] - - - - - 9 - - - Consume message - - - - - ref - - - Send notification to Participant (Payer) - - - - - 10 - - - Send callback notification - - - - - opt - - - [action IN ['timeout-reserved', 'bulk-timeout-reserved']] - - - - - 11 - - - Consume message - - - - - ref - - - Send notification to Participant (Payee) - - - - - 12 - - - Send callback notification - + + 3.1.0. Transfer Timeout (incl. Bulk Transfer) + + Financial Service Providers + + ML API Adapter Service + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DFSP1 + Payer + + + DFSP1 + Payer + + + DFSP2 + Payee + + + DFSP2 + Payee + + + ML API + Adapter + + + ML API + Adapter + + + ML API Notification + Event Handler + + + ML API Notification + Event Handler + + + Transfer Timeout + Handler + + + Transfer Timeout + Handler + + + + + topic- + transfer-position + + + topic- + transfer-position + + + topic-event + + + topic-event + Position Event + Handler + + + Position Event + Handler + + + + + topic- + notification + + + topic- + notification + Bulk Processing + Handler + + + Bulk Processing + Handler + + + + + topic- + bulk-processing + + + topic- + bulk-processing + + + + + + + Transfer Expiry + + + ref + Timeout Handler Consume + + + + alt + [transferStateId == 'RECEIVED_PREPARE'] + + + alt + [Regular Transfer] + + + 1 + Produce message + + [Individual Transfer from a Bulk] + + + 2 + Produce message + + [transferStateId == 'RESERVED'] + + + 3 + Produce message + + + 4 + Consume message + + + ref + Position Hander Consume (Timeout) + + + + alt + [Regular Transfer] + + + 5 + Produce message + + [Individual Transfer from a Bulk] + + + 6 + Produce message + + + opt + [action IN ['bulk-timeout-received', 'bulk-timeout-reserved']] + + + 7 + Consume message + + + ref + Bulk Processing Consume + + + + 8 + Produce message + + + opt + [action IN ['timeout-received', 'timeout-reserved', 'bulk-timeout-received', 'bulk-timeout-reserved']] + + + 9 + Consume message + + + ref + Send notification to Participant (Payer) + + + + alt + [Timeout before any processing] + + + PUT /bulkTransfers/<ID> + { + headers: <bulkTransferHeaders>, + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + ] + } + } + + [Timeout in middle of processing] + + + PUT /bulkTransfers/<ID> + { + headers: <bulkTransferHeaders>, + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "transferId": <ID>, + "fulfilment": <fulfilment> + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + ] + } + } + + + 10 + Send callback notification + + + opt + [action IN ['timeout-reserved', 'bulk-timeout-reserved']] + + + 11 + Consume message + + + ref + Send notification to Participant (Payee) + + + + alt + [Timeout before any processing] + + + PUT /bulkTransfers/<ID> + { + headers: <bulkTransferHeaders>, + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + ] + } + } + + [Timeout in middle of processing] + + + PUT /bulkTransfers/<ID> + { + headers: <bulkTransferHeaders>, + body: { + "bulkTransferState": "COMPLETED", + "completedTimestamp": "2022-08-18T01:00:24.407Z", + "individualTransferResults": [ + { + "transferId": <ID>, + "fulfilment": <fulfilment> + }, + { + "errorInformation": { + "errorCode": "3303", + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + "transferId": <ID> + }, + ] + } + } + + + 12 + Send callback notification + diff --git a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.plantuml b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.plantuml index 40caba5ae..1c9343431 100644 --- a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.plantuml +++ b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.plantuml @@ -126,7 +126,7 @@ group Timeout Handler Consume deactivate POS_DAO end - + group Prepare data and return the list for expiration TIMEOUT_HANDLER -> POS_DAO: Prepare data and get transfers to be expired activate POS_DAO @@ -208,7 +208,7 @@ group Timeout Handler Consume POS_DAO -> DB: Get list of transfers to be expired with current state hnote over DB #lightyellow - SELECT tt.*, tsc.transferStateId, tp1.participantCurrencyId payerParticipantId, + SELECT tt.*, tsc.transferStateId, tp1.participantCurrencyId payerParticipantId, tp2.participantCurrencyId payeeParticipantId, bta.bulkTransferId FROM **transferTimeout** tt JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId @@ -264,8 +264,8 @@ group Timeout Handler Consume }, payload: { "errorInformation": { - "errorCode": 3300, - "errorDescription": "Generic expired error", + "errorCode": 3303, + "errorDescription": "Transfer expired", "extensionList": } } @@ -311,8 +311,8 @@ group Timeout Handler Consume }, payload: { "errorInformation": { - "errorCode": 3300, - "errorDescription": "Generic expired error", + "errorCode": 3303, + "errorDescription": "Transfer expired", "extensionList": } } @@ -350,8 +350,8 @@ group Timeout Handler Consume headers: , payload: { "errorInformation": { - "errorCode": 3300, - "errorDescription": "Generic expired error", + "errorCode": 3303, + "errorDescription": "Transfer expired", "extensionList": } } @@ -387,8 +387,8 @@ group Timeout Handler Consume headers: ,, payload: { "errorInformation": { - "errorCode": 3300, - "errorDescription": "Generic expired error", + "errorCode": 3303, + "errorDescription": "Transfer expired", "extensionList": } } diff --git a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg index 4f687da29..fc0c4635b 100644 --- a/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg +++ b/docs/technical/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg @@ -1,1340 +1,605 @@ - + + - - - - - + + + + + - - 3.1.1. Timeout Handler Consume (incl. Bulk Transfer) - - - - Central Service - - - - - - - - - - - - - - Transfer Timeout - - - Handler - - - - - Transfer Timeout - - - Handler - - - - - - - topic- - - - transfer-position - - - - - topic- - - - transfer-position - - - - - topic- - - - notification - - - - - topic- - - - notification - - - - - topic-event - - - - - topic-event - - - - - topic- - - - bulk-processing - - - - - topic- - - - bulk-processing - - - Position DAO - - - - - Position DAO - - - - - Segment DAO - - - - - Segment DAO - - - - - Central Store - - - - - Central Store - - - - - - - - Timeout Handler Consume - - - - - Persist Event Information - - - - - 1 - - - Publish event information - - - - - ref - - - Event Handler Consume - - - - - Get previous checkpoint of last record processed (Lower limit for inclusion) - - - - - 2 - - - Get last segment as @intervalMin - - - - - 3 - - - Get last segment as @intervalMin - - - - SELECT value INTO @intervalMin - - - FROM - - - segment - - - WHERE segmentType = 'timeout' - - - AND enumeration = 0 - - - AND tableName = 'transferStateChange' - - - - - 4 - - - Return @intervalMin - - - - - 5 - - - Return @intervalMin - - - - - opt - - - [@intervalMin IS NULL => segment record NOT FOUND] - - - - - 6 - - - Set @intervalMin = 0 - - - - - Do Cleanup - - - - - 7 - - - Clean up transferTimeout from finalised transfers - - - - - 8 - - - Clean up transferTimeout from finalised transfers - - - - DELETE tt - - - FROM - - - transferTimeout - - - AS tt - - - JOIN (SELECT tsc.transferId, MAX(tsc.transferStateChangeId) maxTransferStateChangeId - - - FROM - - - transferTimeout - - - tt1 - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferId = tt1.transferId - - - GROUP BY transferId) ts - - - ON ts.transferId = tt.transferId - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferStateChangeId = ts.maxTransferStateChangeId - - - WHERE tsc.transferStateId IN ('RECEIVED_FULFIL', 'COMMITTED', 'FAILED' - - - , 'EXPIRED', 'REJECTED', 'EXPIRED_PREPARED', 'EXPIRED_RESERVED', 'ABORTED') - - - - - 9 - - - Return success - - - - - Determine IntervalMax (Upper limit for inclusion) - - - - - 10 - - - Get last transferStateChangeId as @intervalMax - - - - - 11 - - - Get last transferStateChangeId as @intervalMax - - - - SELECT MAX(transferStateChangeId) INTO @intervalMax - - - FROM - - - transferStateChange - - - - - 12 - - - Return @intervalMax - - - - - 13 - - - Return @intervalMax - - - - - Prepare data and return the list for expiration - - - - - 14 - - - Prepare data and get transfers to be expired - - - - - DB TRANSACTION - - - - - 15 - - - transactionTimestamp - - - = now() - - - - - 16 - - - Insert all new transfers still in processing state - - - - INSERT INTO - - - transferTimeout - - - (transferId, expirationDate) - - - SELECT t.transferId, t.expirationDate - - - FROM - - - transfer - - - t - - - JOIN (SELECT transferId, MAX(transferStateChangeId) maxTransferStateChangeId - - - FROM - - - transferStateChange - - - WHERE transferStateChangeId > @intervalMin - - - AND transferStateChangeId <= @intervalMax - - - GROUP BY transferId) ts - - - ON ts.transferId = t.transferId - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferStateChangeId = ts.maxTransferStateChangeId - - - WHERE tsc.transferStateId IN ('RECEIVED_PREPARE', 'RESERVED') - - - - - 17 - - - Insert transfer state ABORTED for - - - expired RECEIVED_PREPARE transfers - - - - INSERT INTO - - - transferStateChange - - - SELECT tt.transferId, 'EXPIRED_PREPARED' AS transferStateId, 'Aborted by Timeout Handler' AS reason - - - FROM - - - transferTimeout - - - tt - - - JOIN ( - - - -- Following subquery is reused 3 times and may be optimized if needed - - - SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId - - - FROM - - - transferStateChange - - - tsc1 - - - JOIN - - - transferTimeout - - - tt1 - - - ON tt1.transferId = tsc1.transferId - - - GROUP BY tsc1.transferId) ts - - - ON ts.transferId = tt.transferId - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferStateChangeId = ts.maxTransferStateChangeId - - - WHERE tt.expirationDate < {transactionTimestamp} - - - AND tsc.transferStateId = 'RECEIVED_PREPARE' - - - - - 18 - - - Insert transfer state EXPIRED for - - - expired RESERVED transfers - - - - INSERT INTO - - - transferStateChange - - - SELECT tt.transferId, 'RESERVED_TIMEOUT' AS transferStateId, 'Expired by Timeout Handler' AS reason - - - FROM - - - transferTimeout - - - tt - - - JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId - - - FROM - - - transferStateChange - - - tsc1 - - - JOIN - - - transferTimeout - - - tt1 - - - ON tt1.transferId = tsc1.transferId - - - GROUP BY tsc1.transferId) ts - - - ON ts.transferId = tt.transferId - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferStateChangeId = ts.maxTransferStateChangeId - - - WHERE tt.expirationDate < {transactionTimestamp} - - - AND tsc.transferStateId = 'RESERVED' - - - - - 19 - - - Update segment table to be used for the next run - - - - IF @intervalMin = 0 - - - INSERT - - - INTO - - - segment - - - (segmentType, enumeration, tableName, value) - - - VALUES ('timeout', 0, 'transferStateChange', @intervalMax) - - - ELSE - - - UPDATE - - - segment - - - SET value = @intervalMax - - - WHERE segmentType = 'timeout' - - - AND enumeration = 0 - - - AND tableName = 'transferStateChange' - - - - - 20 - - - Get list of transfers to be expired with current state - - - - SELECT tt.*, tsc.transferStateId, tp1.participantCurrencyId payerParticipantId, - - - tp2.participantCurrencyId payeeParticipantId, bta.bulkTransferId - - - FROM - - - transferTimeout - - - tt - - - JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId - - - FROM - - - transferStateChange - - - tsc1 - - - JOIN - - - transferTimeout - - - tt1 - - - ON tt1.transferId = tsc1.transferId - - - GROUP BY tsc1.transferId) ts - - - ON ts.transferId = tt.transferId - - - JOIN - - - transferStateChange - - - tsc - - - ON tsc.transferStateChangeId = ts.maxTransferStateChangeId - - - JOIN - - - transferParticipant - - - tp1 - - - ON tp1.transferId = tt.transferId - - - AND tp1.transferParticipantRoleTypeId = {PAYER_DFSP} - - - AND tp1.ledgerEntryTypeId = {PRINCIPLE_VALUE} - - - JOIN - - - transferParticipant - - - tp2 - - - ON tp2.transferId = tt.transferId - - - AND tp2.transferParticipantRoleTypeId = {PAYEE_DFSP} - - - AND tp2.ledgerEntryTypeId = {PRINCIPLE_VALUE} - - - LEFT JOIN - - - bulkTransferAssociation - - - bta - - - ON bta.transferId = tt.transferId - - - WHERE tt.expirationDate < {transactionTimestamp} - - - - - 21 - - - Return - - - transferTimeoutList - - - - - 22 - - - Return - - - transferTimeoutList - - - - - loop - - - [for each transfer in the list] - - - - - alt - - - [transferTimeoutList.bulkTransferId == NULL (Regular Transfer)] - - - - - alt - - - [transferStateId == 'RECEIVED_PREPARE'] - - - - - Message: - - - { - - - id: <transferId>, - - - from: <payerParticipantId>, - - - to: <payeeParticipantId>, - - - type: application/json, - - - content: { - - - headers: { - - - Content-Length: <Content-Length>, - - - Content-Type: <Content-Type>, - - - Date: <Date>, - - - X-Forwarded-For: <X-Forwarded-For>, - - - FSPIOP-Source: <FSPIOP-Source>, - - - FSPIOP-Destination: <FSPIOP-Destination>, - - - FSPIOP-Encryption: <FSPIOP-Encryption>, - - - FSPIOP-Signature: <FSPIOP-Signature>, - - - FSPIOP-URI: <FSPIOP-URI>, - - - FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> - - - }, - - - payload: { - - - "errorInformation": { - - - "errorCode": 3300, - - - "errorDescription": "Generic expired error", - - - "extensionList": <transferMessage.extensionList> - - - } - - - } - - - }, - - - metadata: { - - - event: { - - - id: <uuid>, - - - type: notification, - - - action: timeout-received, - - - createdAt: <timestamp>, - - - state: { - - - status: 'error', - - - code: <errorInformation.errorCode> - - - description: <errorInformation.errorDescription> - - - } - - - } - - - } - - - } - - - - - 23 - - - Publish Notification event - - - - [transferStateId == 'RESERVED'] - - - - - Message: - - - { - - - id: <transferId>, - - - from: <payerParticipantId>, - - - to: <payeeParticipantId>, - - - type: application/json, - - - content: { - - - headers: { - - - Content-Length: <Content-Length>, - - - Content-Type: <Content-Type>, - - - Date: <Date>, - - - X-Forwarded-For: <X-Forwarded-For>, - - - FSPIOP-Source: <FSPIOP-Source>, - - - FSPIOP-Destination: <FSPIOP-Destination>, - - - FSPIOP-Encryption: <FSPIOP-Encryption>, - - - FSPIOP-Signature: <FSPIOP-Signature>, - - - FSPIOP-URI: <FSPIOP-URI>, - - - FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> - - - }, - - - payload: { - - - "errorInformation": { - - - "errorCode": 3300, - - - "errorDescription": "Generic expired error", - - - "extensionList": <transferMessage.extensionList> - - - } - - - } - - - }, - - - metadata: { - - - event: { - - - id: <uuid>, - - - type: position, - - - action: timeout-reserved, - - - createdAt: <timestamp>, - - - state: { - - - status: 'error', - - - code: <errorInformation.errorCode> - - - description: <errorInformation.errorDescription> - - - } - - - } - - - } - - - } - - - - - 24 - - - Route & Publish Position event - - - - [Individual Transfer from a Bulk] - - - - - alt - - - [transferStateId == 'RECEIVED_PREPARE'] - - - - - Message: - - - { - - - id - - - : <transferTimeoutList.bulkTransferId>, - - - transferId - - - : <transferTimeoutList.transferId>, - - - from: <payerParticipantId>, - - - to: <payeeParticipantId>, - - - type: application/json, - - - content: { - - - headers: <bulkTransferHeaders>, - - - payload: { - - - "errorInformation": { - - - "errorCode": 3300, - - - "errorDescription": "Generic expired error", - - - "extensionList": <transferMessage.extensionList> - - - } - - - } - - - }, - - - metadata: { - - - event: { - - - id: <uuid>, - - - type: bulk-processing, - - - action: bulk-timeout-received, - - - createdAt: <timestamp>, - - - state: { - - - status: 'error', - - - code: <errorInformation.errorCode> - - - description: <errorInformation.errorDescription> - - - } - - - } - - - } - - - } - - - - - 25 - - - Publish to Bulk Processing topic - - - - [transferStateId == 'RESERVED'] - - - - - Message: - - - { - - - id - - - : <transferTimeoutList.bulkTransferId>, - - - transferId - - - : <transferTimeoutList.transferId>, - - - from: <payerParticipantId>, - - - to: <payeeParticipantId>, - - - type: application/json, - - - content: { - - - headers: <bulkTransferHeaders>,, - - - payload: { - - - "errorInformation": { - - - "errorCode": 3300, - - - "errorDescription": "Generic expired error", - - - "extensionList": <transferMessage.extensionList> - - - } - - - } - - - }, - - - metadata: { - - - event: { - - - id: <uuid>, - - - type: position, - - - action: bulk-timeout-reserved, - - - createdAt: <timestamp>, - - - state: { - - - status: 'error', - - - code: <errorInformation.errorCode> - - - description: <errorInformation.errorDescription> - - - } - - - } - - - } - - - } - - - - - 26 - - - Route & Publish Position event - + + 3.1.1. Timeout Handler Consume (incl. Bulk Transfer) + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Transfer Timeout + Handler + + + Transfer Timeout + Handler + + + + + topic- + transfer-position + + + topic- + transfer-position + + + topic- + notification + + + topic- + notification + + + topic-event + + + topic-event + + + topic- + bulk-processing + + + topic- + bulk-processing + Position DAO + + + Position DAO + + + Segment DAO + + + Segment DAO + + + Central Store + + + Central Store + + + + + + + + + + + + + + + + + + + + + + Timeout Handler Consume + + + Persist Event Information + + + 1 + Publish event information + + + ref + Event Handler Consume + + + + Get previous checkpoint of last record processed (Lower limit for inclusion) + + + 2 + Get last segment as @intervalMin + + + 3 + Get last segment as @intervalMin + + SELECT value INTO @intervalMin + FROM + segment + WHERE segmentType = 'timeout' + AND enumeration = 0 + AND tableName = 'transferStateChange' + + + 4 + Return @intervalMin + + + 5 + Return @intervalMin + + + opt + [@intervalMin IS NULL => segment record NOT FOUND] + + + + + 6 + Set @intervalMin = 0 + + + Do Cleanup + + + 7 + Clean up transferTimeout from finalised transfers + + + 8 + Clean up transferTimeout from finalised transfers + + DELETE tt + FROM + transferTimeout + AS tt + JOIN (SELECT tsc.transferId, MAX(tsc.transferStateChangeId) maxTransferStateChangeId + FROM + transferTimeout + tt1 + JOIN + transferStateChange + tsc + ON tsc.transferId = tt1.transferId + GROUP BY transferId) ts + ON ts.transferId = tt.transferId + JOIN + transferStateChange + tsc + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + WHERE tsc.transferStateId IN ('RECEIVED_FULFIL', 'COMMITTED', 'FAILED' + , 'EXPIRED', 'REJECTED', 'EXPIRED_PREPARED', 'EXPIRED_RESERVED', 'ABORTED') + + + 9 + Return success + + + Determine IntervalMax (Upper limit for inclusion) + + + 10 + Get last transferStateChangeId as @intervalMax + + + 11 + Get last transferStateChangeId as @intervalMax + + SELECT MAX(transferStateChangeId) INTO @intervalMax + FROM + transferStateChange + + + 12 + Return @intervalMax + + + 13 + Return @intervalMax + + + Prepare data and return the list for expiration + + + 14 + Prepare data and get transfers to be expired + + + DB TRANSACTION + + + + + 15 + transactionTimestamp + = now() + + + 16 + Insert all new transfers still in processing state + + INSERT INTO + transferTimeout + (transferId, expirationDate) + SELECT t.transferId, t.expirationDate + FROM + transfer + t + JOIN (SELECT transferId, MAX(transferStateChangeId) maxTransferStateChangeId + FROM + transferStateChange + WHERE transferStateChangeId > @intervalMin + AND transferStateChangeId <= @intervalMax + GROUP BY transferId) ts + ON ts.transferId = t.transferId + JOIN + transferStateChange + tsc + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + WHERE tsc.transferStateId IN ('RECEIVED_PREPARE', 'RESERVED') + + + 17 + Insert transfer state ABORTED for + expired RECEIVED_PREPARE transfers + + INSERT INTO + transferStateChange + SELECT tt.transferId, 'EXPIRED_PREPARED' AS transferStateId, 'Aborted by Timeout Handler' AS reason + FROM + transferTimeout + tt + JOIN ( + -- Following subquery is reused 3 times and may be optimized if needed + SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + FROM + transferStateChange + tsc1 + JOIN + transferTimeout + tt1 + ON tt1.transferId = tsc1.transferId + GROUP BY tsc1.transferId) ts + ON ts.transferId = tt.transferId + JOIN + transferStateChange + tsc + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + WHERE tt.expirationDate < {transactionTimestamp} + AND tsc.transferStateId = 'RECEIVED_PREPARE' + + + 18 + Insert transfer state EXPIRED for + expired RESERVED transfers + + INSERT INTO + transferStateChange + SELECT tt.transferId, 'RESERVED_TIMEOUT' AS transferStateId, 'Expired by Timeout Handler' AS reason + FROM + transferTimeout + tt + JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + FROM + transferStateChange + tsc1 + JOIN + transferTimeout + tt1 + ON tt1.transferId = tsc1.transferId + GROUP BY tsc1.transferId) ts + ON ts.transferId = tt.transferId + JOIN + transferStateChange + tsc + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + WHERE tt.expirationDate < {transactionTimestamp} + AND tsc.transferStateId = 'RESERVED' + + + 19 + Update segment table to be used for the next run + + IF @intervalMin = 0 + INSERT + INTO + segment + (segmentType, enumeration, tableName, value) + VALUES ('timeout', 0, 'transferStateChange', @intervalMax) + ELSE + UPDATE + segment + SET value = @intervalMax + WHERE segmentType = 'timeout' + AND enumeration = 0 + AND tableName = 'transferStateChange' + + + 20 + Get list of transfers to be expired with current state + + SELECT tt.*, tsc.transferStateId, tp1.participantCurrencyId payerParticipantId, + tp2.participantCurrencyId payeeParticipantId, bta.bulkTransferId + FROM + transferTimeout + tt + JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + FROM + transferStateChange + tsc1 + JOIN + transferTimeout + tt1 + ON tt1.transferId = tsc1.transferId + GROUP BY tsc1.transferId) ts + ON ts.transferId = tt.transferId + JOIN + transferStateChange + tsc + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + JOIN + transferParticipant + tp1 + ON tp1.transferId = tt.transferId + AND tp1.transferParticipantRoleTypeId = {PAYER_DFSP} + AND tp1.ledgerEntryTypeId = {PRINCIPLE_VALUE} + JOIN + transferParticipant + tp2 + ON tp2.transferId = tt.transferId + AND tp2.transferParticipantRoleTypeId = {PAYEE_DFSP} + AND tp2.ledgerEntryTypeId = {PRINCIPLE_VALUE} + LEFT JOIN + bulkTransferAssociation + bta + ON bta.transferId = tt.transferId + WHERE tt.expirationDate < {transactionTimestamp} + + + 21 + Return + transferTimeoutList + + + 22 + Return + transferTimeoutList + + + loop + [for each transfer in the list] + + + alt + [transferTimeoutList.bulkTransferId == NULL (Regular Transfer)] + + + alt + [transferStateId == 'RECEIVED_PREPARE'] + + + Message: + { + id: <transferId>, + from: <payerParticipantId>, + to: <payeeParticipantId>, + type: application/json, + content: { + headers: { + Content-Length: <Content-Length>, + Content-Type: <Content-Type>, + Date: <Date>, + X-Forwarded-For: <X-Forwarded-For>, + FSPIOP-Source: <FSPIOP-Source>, + FSPIOP-Destination: <FSPIOP-Destination>, + FSPIOP-Encryption: <FSPIOP-Encryption>, + FSPIOP-Signature: <FSPIOP-Signature>, + FSPIOP-URI: <FSPIOP-URI>, + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + }, + payload: { + "errorInformation": { + "errorCode": 3303, + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + } + }, + metadata: { + event: { + id: <uuid>, + type: notification, + action: timeout-received, + createdAt: <timestamp>, + state: { + status: 'error', + code: <errorInformation.errorCode> + description: <errorInformation.errorDescription> + } + } + } + } + + + 23 + Publish Notification event + + [transferStateId == 'RESERVED'] + + + Message: + { + id: <transferId>, + from: <payerParticipantId>, + to: <payeeParticipantId>, + type: application/json, + content: { + headers: { + Content-Length: <Content-Length>, + Content-Type: <Content-Type>, + Date: <Date>, + X-Forwarded-For: <X-Forwarded-For>, + FSPIOP-Source: <FSPIOP-Source>, + FSPIOP-Destination: <FSPIOP-Destination>, + FSPIOP-Encryption: <FSPIOP-Encryption>, + FSPIOP-Signature: <FSPIOP-Signature>, + FSPIOP-URI: <FSPIOP-URI>, + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + }, + payload: { + "errorInformation": { + "errorCode": 3303, + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + } + }, + metadata: { + event: { + id: <uuid>, + type: position, + action: timeout-reserved, + createdAt: <timestamp>, + state: { + status: 'error', + code: <errorInformation.errorCode> + description: <errorInformation.errorDescription> + } + } + } + } + + + 24 + Route & Publish Position event + + [Individual Transfer from a Bulk] + + + alt + [transferStateId == 'RECEIVED_PREPARE'] + + + Message: + { + + id + : <transferTimeoutList.bulkTransferId>, + + transferId + : <transferTimeoutList.transferId>, + from: <payerParticipantId>, + to: <payeeParticipantId>, + type: application/json, + content: { + headers: <bulkTransferHeaders>, + payload: { + "errorInformation": { + "errorCode": 3303, + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + } + }, + metadata: { + event: { + id: <uuid>, + type: bulk-processing, + action: bulk-timeout-received, + createdAt: <timestamp>, + state: { + status: 'error', + code: <errorInformation.errorCode> + description: <errorInformation.errorDescription> + } + } + } + } + + + 25 + Publish to Bulk Processing topic + + [transferStateId == 'RESERVED'] + + + Message: + { + + id + : <transferTimeoutList.bulkTransferId>, + + transferId + : <transferTimeoutList.transferId>, + from: <payerParticipantId>, + to: <payeeParticipantId>, + type: application/json, + content: { + headers: <bulkTransferHeaders>,, + payload: { + "errorInformation": { + "errorCode": 3303, + "errorDescription": "Transfer expired", + "extensionList": <transferMessage.extensionList> + } + } + }, + metadata: { + event: { + id: <uuid>, + type: position, + action: bulk-timeout-reserved, + createdAt: <timestamp>, + state: { + status: 'error', + code: <errorInformation.errorCode> + description: <errorInformation.errorDescription> + } + } + } + } + + + 26 + Route & Publish Position event +