Hi Dishita, James,

Great initiative on FINERACT-2591.

To address James’s concern regarding performance overhead: standard I/O
logging operations on the critical path can easily become bottlenecks under
high concurrency. To keep this strictly $O(1)$ and lightweight, we should
execute this missing-key check at the absolute edge of the HTTP stack.

By placing this logging logic inside the OncePerRequestFilter boundary
(mapped out in FINERACT-2485
<https://issues.apache.org/jira/browse/FINERACT-2485>) rather than deeper
in the Spring routing layer, we avoid consuming heavy Tomcat threads for
malformed requests. Wrapping it in a conditional log.debug tied to the
global idempotency toggle will guarantee zero performance penalty when
disabled.

Dishita, I am happy to coordinate with you on the filter boundary once the
GSoC coding period opens so your PR drops in seamlessly.

Regards,

Mohammed Saifulhuq

On Thu, Apr 23, 2026 at 8:40 AM James Dailey <[email protected]> wrote:

> Dishita - I think the documentation and client-side pieces are the way to
> go.  In that case, the documentation at Fineract is only one side of the
> contract. That can be better documented and logged.
>
> I think logging when a key is missing is a useful feature, provided it
> doesn't create additional overhead and can be "turned off" when other
> enforcement mechanisms are in place.
>
>
>
>
> On Wed, Apr 22, 2026 at 12:37 PM Dishita Suyal <[email protected]>
> wrote:
>
>> Hi,
>>
>> I’ve created a JIRA issue to improve observability by logging when the
>> Idempotency-Key header is missing:
>>
>> FINERACT-2591
>>
>> Happy to work on this if it aligns with the project direction.
>>
>> Thanks,
>> Dishita
>>
>> On Thu, Apr 23, 2026 at 12:45 AM Dishita Suyal <[email protected]>
>> wrote:
>>
>>> Hi everyone,
>>>
>>> Thank you for raising and discussing this topic — it was very insightful.
>>>
>>> From my understanding, enforcing deterministic idempotency on the server
>>> side when the client does not provide a key could introduce risks,
>>> especially in financial workflows where identical payloads may still
>>> represent distinct business intents (e.g., multiple valid repayments within
>>> a short time window).
>>>
>>> It seems more aligned with the current architecture that idempotency
>>> remains a client-driven contract, with the server enforcing it only when an
>>> explicit key is provided.
>>>
>>> Would it make sense to instead focus on improving client-side guidance
>>> or safeguards (for example, better documentation or warnings when the key
>>> is missing), rather than introducing server-side fallback behavior?
>>>
>>> I’d appreciate your thoughts on this.
>>>
>>> Regards,
>>> Dishita
>>>
>>> On Fri, Apr 17, 2026 at 5:30 PM Mohammed Saifulhuq <
>>> [email protected]> wrote:
>>>
>>>> Hi Lukman, Adam,
>>>>
>>>> I completely agree with Adam's assessment. Enforcing server-side
>>>> deterministic key generation based solely on payload introduces severe
>>>> risks to core banking operations.
>>>>
>>>> In microfinance, it is entirely valid for a client to submit two
>>>> identical business intents in a short window (e.g., making two separate $50
>>>> loan repayments on the same day). If the server automatically generates a
>>>> fallback key based on that payload, the Idempotency Filter will falsely
>>>> flag the second legitimate payment as a duplicate and block it with a 409
>>>> Conflict. This corrupts the ledger.
>>>>
>>>> Idempotency must remain a strict client-server contract. The client
>>>> owns the intent; the server enforces the lock.
>>>>
>>>> In the system-wide idempotency architecture mapped out for
>>>> FINERACT-2169 / FINERACT-2485, this is handled explicitly to ensure zero
>>>> regression:
>>>>
>>>> 1. The OncePerRequestFilter strictly targets the Idempotency-Key HTTP
>>>> header.
>>>>
>>>> 2. If the header is missing, the filter bypasses the PostgreSQL lookup
>>>> entirely ($O(1)$ exit) and allows the request to pass to the legacy
>>>> command processing pipeline.
>>>>
>>>> 3. Payload canonicalization and hashing are used strictly for integrity
>>>> verification (ensuring a client doesn't maliciously reuse the same key for
>>>> a different payload), never for fallback key generation.
>>>>
>>>> The global configuration flag allows legacy clients to continue
>>>> operating without keys, while modern clients can opt-in to the safe
>>>> execution path.
>>>>
>>>> Regards,
>>>>
>>>> Mohammed Saifulhuq
>>>>
>>>> On Fri, Apr 17, 2026 at 3:53 PM Ádám Sághy <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> Thank you for raising this topic!
>>>>>
>>>>> In my understanding, if no idempotency key is provided, we should not
>>>>> enforce idempotent behavior.
>>>>>
>>>>> While I understand where the fallback logic is coming from, I am
>>>>> hesitant to go on that path:
>>>>>
>>>>>
>>>>>    - “Same payload” is not always the same business intent.
>>>>>    - shifts idempotency responsibility from the client contract to
>>>>>    server inference
>>>>>    - it can mean blocking a valid transaction
>>>>>
>>>>>
>>>>> For these reasons, I am not sure we should enforce this as default
>>>>> fallback. Maybe it is as an optional thing would be better?
>>>>>
>>>>> Regards,
>>>>> Adam
>>>>>
>>>>>
>>>>> On Apr 9, 2026, at 2:07 PM, elnafateh <[email protected]> wrote:
>>>>>
>>>>> Hi everyone,
>>>>>
>>>>> I would like to raise a discussion regarding idempotency handling in
>>>>> Fineract, specifically when a client does not provide an idempotency key.
>>>>> Problem
>>>>>
>>>>> Currently, if a client omits the idempotency key, the system may
>>>>> generate a random UUID per request. In retry scenarios, this can lead to
>>>>> duplicate processing of the same logical operation.
>>>>>
>>>>> A typical scenario:
>>>>>
>>>>>    1.
>>>>>
>>>>>    Client sends a request (e.g., funds transfer)
>>>>>    2.
>>>>>
>>>>>    Server processes and commits successfully
>>>>>    3.
>>>>>
>>>>>    Client does not receive the response (e.g., network timeout)
>>>>>    4.
>>>>>
>>>>>    Client retries the same request without an idempotency key
>>>>>    5.
>>>>>
>>>>>    A new UUID is generated → request is treated as a new operation
>>>>>
>>>>> This can result in unintended duplicate transactions (e.g., double
>>>>> spending).
>>>>> Proposal
>>>>>
>>>>> Instead of generating a random UUID, generate a deterministic
>>>>> idempotency key based on:
>>>>>
>>>>>    -
>>>>>
>>>>>    Request payload
>>>>>    -
>>>>>
>>>>>    Relevant context (e.g., clientId, entityName,ActionName etc)
>>>>>    -
>>>>>
>>>>>    Optional bounded time window
>>>>>
>>>>> This ensures that repeated identical requests map to the same
>>>>> idempotency key, even when the client does not explicitly provide one.
>>>>> Open Questions
>>>>>
>>>>>    -
>>>>>
>>>>>    Should the system enforce idempotency even when the client does
>>>>>    not provide a key?
>>>>>    -
>>>>>
>>>>>    Is deterministic key generation an acceptable fallback strategy?
>>>>>    -
>>>>>
>>>>>    Are there concerns around edge cases (e.g., payload variations,
>>>>>    time window constraints)?
>>>>>
>>>>> I would really appreciate feedback on whether this problem is valid in
>>>>> the context of Fineract and if this approach aligns with the project’s
>>>>> design principles.
>>>>>
>>>>> Thanks,
>>>>> Lukman Fateh
>>>>>
>>>>>
>>>>>

Reply via email to