[ 
https://issues.apache.org/jira/browse/FINERACT-3004?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18132773#comment-18132773
 ] 

Piotr Wargulak commented on FINERACT-3004:
------------------------------------------

See Apache Dev mailing list thread: FINERACT-3004: COB silently rolls back a 
whole chunk when one loan's business step fails: loans stay locked with no 
error and the job reports success

> COB silently rolls back a whole chunk when one loan's business step fails: 
> loans stay locked with no error and the job reports success
> --------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: FINERACT-3004
>                 URL: https://issues.apache.org/jira/browse/FINERACT-3004
>             Project: Apache Fineract
>          Issue Type: Bug
>            Reporter: Piotr Wargulak
>            Assignee: Piotr Wargulak
>            Priority: Major
>         Attachments: FeignWorkingCapitalLoanCobBusinessStepFailureTest.java, 
> LoanCobBusinessStepFailureTest.java
>
>
> When a business step throws for one loan during a scheduled Loan COB or 
> Working Capital Loan COB run, every loan of that chunk is left behind without 
> any trace:
>  * the loans keep their {{LOAN_COB_CHUNK_PROCESSING}} lock with {{error}} 
> empty, so the lock is never overrulable;
>  * none of them gets {{last_closed_business_date}} moved, and none of the 
> chunk's work is kept, including the loans that had no problem;
>  * the step ends {{COMPLETED}} and the job run is recorded as {{{}success{}}}.
> What happens, step by step (Spring Batch 6.0.5, {{{}ChunkOrientedStep{}}}):
>  # The item processor runs {{{}COBBusinessStepServiceImpl#run{}}}, which is 
> {{@Transactional}} and joins the chunk transaction. The step's exception 
> leaves that method, so the JPA transaction manager marks the chunk 
> transaction rollback-only ("Participating transaction failed - marking 
> existing transaction as rollback-only").
>  # The worker step is fault tolerant with an immediate retry policy, so 
> {{doProcess}} retries the item in the same transaction and persistence 
> context. Two outcomes:
>  ** the retry succeeds (it can: the first attempt's changes are still in the 
> persistence context) and nothing is reported at all;
>  ** the retries are used up: {{onProcessError}} is called, the item is 
> skipped ({{{}doSkipInProcess{}}}), and the chunk goes on.
>  # After the chunk, {{doExecute}} finds 
> {{{}transactionStatus.isRollbackOnly(){}}}, rolls back and returns 
> ({{{}ChunkOrientedStep:380-389{}}}). No exception, no listener, no scan; the 
> next chunk starts and the step completes.
> A process skip therefore cannot work while processing writes in the chunk 
> transaction: the skipped item has already doomed the transaction of the items 
> processed with it. 
> In the retries-used-up case, 
> {{AbstractLoanItemListener#updateAccountLockWithError}} also failed for us 
> with {{UnexpectedRollbackException}} (Working Capital, on our build); we have 
> not established why its {{REQUIRES_NEW}} transaction is rollback-only.
> *Steps to reproduce* 
> _(a GL closure on the COB date makes one loan's business step fail)_
> Two attached integration tests, each with two loans of one chunk: one whose 
> step posts a journal entry on the COB date, and one with no accounting, which 
> posts nothing and so is not concerned by the closure.
>  * {{LoanCobBusinessStepFailureTest}} (Loan COB, based on 
> {{{}LoanAccrualTransactionOnChargeSubmittedDateTest{}}}): business date 
> 2023-03-03 with {{charge-accrual-date}} = {{{}submitted-date{}}}; a 
> single-repayment loan with periodic accrual accounting and a penalty and a 
> fee charge, and a second loan on a product from the same template with 
> accounting none. Business date 2023-03-04, {{POST /glclosures}} for office 1 
> on 2023-03-03, run the Loan COB job. 
> {{LoanAccrualsProcessingServiceImpl#addPeriodicAccruals}} throws 
> {{{}JournalEntryInvalidException{}}}.
>  * {{FeignWorkingCapitalLoanCobBusinessStepFailureTest}} (Working Capital 
> Loan COB): a loan on an accrual ({{{}ACC_DEF_REV_AM{}}}) product with a 
> discount and a repayment on 2026-01-02, and a loan on a product without 
> accounting. Business date 2026-01-03, closure on 2026-01-02, run the Working 
> Capital Loan COB job. 
> {{WorkingCapitalLoanDiscountFeeAmortizationServiceImpl#processDiscountFeeAmortization}}
>  throws {{{}JournalEntryInvalidException{}}}.
> On develop 537e19aaa9 (PostgreSQL) both tests fail on the loan with nothing 
> to post: {{expected: <2023-03-03> but was: <null>}} and {{{}expected: 
> <2026-01-02> but was: <null>{}}}. After the runs both loans of each job keep 
> {{LOAN_COB_CHUNK_PROCESSING}} with no error, and both job runs are recorded 
> as {{{}success{}}}. The application log shows the exception, then 
> "Transactional code has requested rollback".
> {*}Possible directions{*}:
>  * run each loan's business steps in their own transaction (a nested one, or 
> REQUIRES_NEW plus writing the loan in it), so one loan's failure does not 
> doom the chunk; this changes the semantics FINERACT-2684 settled;
>  * on a process failure, roll the chunk back and process it again without the 
> failed loan, recording the error on its lock in an independent transaction 
> (as Spring Batch 5's fault-tolerant chunk processor did for a process skip);
>  * at the very least, fail the step when a chunk is rolled back this way, so 
> the job does not report success while loans are left locked.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to