0
votes

I have 5 nodes & 1 Notary node corda private network and a web client with UI & RESTful services.

There are quite a few states and its attributes that are managed by users using the UI. I need to understand how to handle timeouts and avoid multiple updates or Errors

Scenario 1

  1. User is viewing a specific un-consumed current state of a feature.
  2. User performs an edit and updates the state

Upon receiving the request RESTful component use CORDA RPCClient to start the flow. It sets the timeout value e.g. 2 secs

CORDA flow runs the configured rules and it has to sync / collect signatures from all the participating nodes (4). Complete processing takes more than 2 secs (Some file processing, multiple states update etc. I can change the timeout to higher value based on specific use cases. It can surely happen anytime. Need to understand what is the recommended way of handling)

As time taken is higher than provided, CORDA RPCClient throws exception. For the RESTFul service / User transaction has failed.

Behind the scenes CORDA is processing and collecting signatures and updating nodes. From CORDA perspective everything looks fine and changed set is committed to the ledger.

Question:

  1. Is there a way to know transaction submitted is in progress so RESTful service should wait

  2. If user submits again we do check for transaction hash is the latest one associated with unconsumed state and reject if not (It was provided to UI while querying.

  3. Any recommended way of handling.

Scenario 2

  1. User viewing a specific un-consumed current state of a feature.
  2. User performs an edit and updates the state

Upon receiving the request RESTful component use CORDA RPCClient to start the flow. It sets the timeout value e.g. 2 secs

CORDA flow runs the configured rules and it has to sync / collect signatures from all the participating nodes (4). One of the nodes is down or not reachable. Flow hangs / waits for the node to be live again.

RESTFul service / UI receives a timeout exception. User refreshes the view and submits the change again. Querying the current node will return old data and user will try to make change again and submit. Same will happen at CORDA layer transaction will be of latest unconsumed state (comparing the tx hash as state is not committed, it will proceed further and will hang / waits for the node to be live again. It waits for long time i have waited for a minute it did not quite trying.

Now the node comes up and will be syncing with peers. Notary will give exception as there are two states / requests pending to form the next state in chain. Transaction fails.

Question:

  1. Is there a way to know transaction submitted is in progress so RESTful service should wait

  2. Any recommended way of handling.

  3. Is there a way to provide timeout values for node communication.

  4. Do i need to keep monitoring if the node is active or not and accordingly tailor user experience.

Appreciate all the help and support for above issue. Please let me know if there is any additional information needed.

1

1 Answers

1
votes

Timeouts

As of Corda 3.3, there is no way to set a timeout either on a Corda RPC request, a flow, or a message to another node. If another node is down when you try to contact it as part of a flow, the message will simply remain in your outbound message queue until it can be successfully delivered.

Checking flow progress

Each flow has a unique run ID. When you start a flow via RPC (e.g. using CordaRPCOps.startFlowDynamic), you get back a FlowHandle. The flow's unique run ID is then available via FlowHandle.id. Once you have this ID, you can check whether the flow is still in progress by checking whether it is still present in the list of current state machines (i.e. flows):

val flowInProgress = flowHandle.id in cordaRPCOps.stateMachinesSnapshot().map { it.id }

You can also monitor the state machine manager to wait until the flow completes, then get its result:

val flowUpdates = cordaRPCOps.stateMachinesFeed().updates
flowUpdates.subscribe {
    if (it.id == flowHandle.id && it is StateMachineUpdate.Removed) {
        val int = it.result.getOrThrow()
        // Handle result.
    }
}

Handling duplicate requests

The flow will throw an exception if you try and consume the same state twice, either when you query the vault to retrieve the state or when you try to notarise the transaction. I'd suggest letting the user start the flow again, then handling any double-spend errors appropriately and reflecting them on the front-end (e.g. via an error message and automatic refresh).