adamsaghy commented on PR #5951:
URL: https://github.com/apache/fineract/pull/5951#issuecomment-4766795369

   **Orphaned‑lock cleanup is weaker than Loan's and may unlock un‑processed 
accounts.**
   Loan's `deleteOrphanedLocksForProcessedAccounts` only removes a lock when it 
can prove the account was actually processed:
   ```
   WHERE lck.error IS NULL
     AND lck.lockPlacedOnCobBusinessDate IS NOT NULL
     AND lck.lockOwner IN :lockOwners
     AND EXISTS (SELECT l FROM Loan l
                 WHERE l.id = lck.loanId
                   AND l.lastClosedBusinessDate = 
lck.lockPlacedOnCobBusinessDate)   ← key guard
   ```                
   The Savings query 
(`SavingsAccountLockRepository.removeOrphanedLocksForProcessedAccounts`) drops 
that correlated `EXISTS`:
   `delete ... where lck.lockPlacedOnCobBusinessDate is not null and lck.error 
is null
     and lck.lockOwner = SAVINGS_COB_CHUNK_PROCESSING`
   
   Without the `lastClosedBusinessDate == lockPlacedOnCobBusinessDate` check, 
"no error recorded" is treated as "successfully processed." If a chunk fails in 
a path that doesn't write an error onto the lock (worker/JVM crash, a skip that 
only logs, any exception that bypasses 
`ChunkProcessingSavingsItemListener.updateLockError`), this tasklet will still 
delete the lock and silently treat the account as done — exactly the case 
Loan's `EXISTS` clause was added to prevent. I'd add the same correlated check 
against `SavingsAccount.lastClosedBusinessDate`. (Minor, related: Loan cleans 
both COB lock owners via `COB_LOCK_OWNERS`; Savings only handles 
`SAVINGS_COB_CHUNK_PROCESSING` — acceptable while inline COB isn't implemented, 
but worth a note.)
   
   **Duplication**
   
   The framework already has generalized COB base types that Loan extends; 
Savings re‑implements them as standalone copies rather than 
reusing/parameterizing them:
   
   - `SavingsCOBPartitioner` re‑inlines all of `CommonPartitioner` (the 
`isEmpty→stopJob`, `StopWatch`, partition‑to‑context logic) instead of 
extending it.
   - `SavingsContextAwareTaskDecorator` is a byte‑for‑byte copy of the generic 
`ContextAwareTaskDecorator` (no savings‑specific logic).
   - `SavingsItemReader.filterRemainingData` duplicates 
`BeforeStepLockingItemReaderHelper.filterRemainingData`.
   - `SavingsLockingService/SavingsLockingServiceImpl` duplicate 
`LockingService/AbstractLockingService` instead of extending it. (Partly 
justified: the shared AbstractLockingService hardcodes the loan_id column, so 
reuse needs that column parameterized — but the cleaner fix is to generalize 
the base, not fork it.)
   - `UnlockProcessedSavingsTasklet` re‑implements 
`UnlockProcessedAccountsTasklet<T>` with a direct repository call instead of 
going through the `AccountLockService<T>` abstraction.
   
   One cosmetic note: the partitioner stores the COB parameter under a new 
`SavingsCOBConstant.SAVINGS_COB_PARAMETER` key rather than the shared 
`COBConstant.COB_PARAMETER`; it's internally consistent (reader and apply‑lock 
read the same key), just inconsistent with the shared constant.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to