View Issue Details

IDProjectCategoryView StatusLast Update
0007251Talerwallet-corepublic2022-11-04 19:52
Reportersebasjm Assigned ToFlorian Dold Resolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicator 
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Product Versiongit (master) 
Target Version0.9Fixed in Version0.9 
Summary0007251: split operation from other database records (purchase, exchange... )
DescriptionCopy from the previous discussion. We should use this ticket for further discussion.

------

Here is my first iteration of the idea:

struct
---------------

interface Operation {
  recordId: string;
  type: PendingTaskInfo.type
  active: boolean;
  LastError
  RetryInfo
}

the operation primary key is composite by type + recordId (exchange id for exchange-update, orderId for proposals), rationale:
 - there should not be two tasks from the same entity
 - the algorithm should be able to find a pending operation for a known record

 * givesLifeness is defined by task type, no need to keep it in the database.
 * timestampDue is calculated by nextRetry in retryInfo

active: does this operation need to run again? for exchange-update it will always be true and for deposits is true when it doesn't have timestampFinished.
The change here is that now the operation algorithm is not responsible for defining when an operation is active (like gatherProposalPending), the domain logic should define this (exchange or deposit) in its own handler. (see handlerResult below)

RetryInfo and LastError stay the same, but they are no more in the EntityRecords (I have counted 9 records approx with this info)


algorithm
--------------

getPendingOperations(): returns operations with active = true

processOnePendingOperation(taskType, recordId)
 - get the row from the database/cache if exists or create it if don't
 - update retryInfo, increment counter
 - get the entity record (skip if it doesn't)
 - call operation handler with the entityRecord
 - check if error, save lastError (also notify async operation error with task type and recordId )
 - algo, update active flag based on the handler result
 - return last state (also notify async operation update with task type and recordId)

This function will be called periodically (by the retryPolicy) and can also be called from user interaction. If the latter should also take the latest state from the database (or create it) and update it (I found that retryTransaction in transaction.ts do this)

Note that the operation handler should know nothing about retry, forceNow, lastError and the operation itself. It just works and updates the EntityRecord.
The operation logic also knows nothing about the entityRecord, it just needs to handle the case that the operation is still active but the record is not found. In that case, I think we can consider ignoring the situation.

Handler should return
interface HandlerResult<T> {
  pending: boolean;
  state: T
}
if pending is true then the operation is still active and will be run again in the next loop. State can be used for sync calls to the handler.

alternatives:
 - operation with a payload: discarded since the record id should have all the information for the handler to be executed
 - compose the type + recordId into one string and make it the id
 - instead of (task type, id) as PK use (entityRecord, operation name, record Id)
 - we may call event instead of operation and transition instead of the handler and every entity record should have a state name: i think that the main difference here is that an operation assumes the state of the entity (operation = event + transition) which is ok for now but I'm worried (maybe too much) when the javascript is upgraded and used with old databases.
TagsNo tags attached.

Required notifications

Address or linkRemarkAdded byNotifiedActions

Activities

Florian Dold

2022-10-31 19:38

manager   ~0019322

This has been fully implemented for a while now. It's called the "operationRetries" store in the DB.

Issue History

Date ModifiedUsernameFieldChange
2022-05-31 14:24sebasjmNew Issue
2022-05-31 14:24sebasjmStatusnew => assigned
2022-05-31 14:24sebasjmAssigned To => sebasjm
2022-08-02 16:12Florian DoldAssigned Tosebasjm => Florian Dold
2022-10-31 19:38Florian DoldStatusassigned => informing
2022-10-31 19:38Florian DoldResolutionopen => fixed
2022-10-31 19:38Florian DoldNote Added: 0019322
2022-10-31 23:19Christian GrothoffFixed in Version => 0.9
2022-10-31 23:19Christian GrothoffTarget Versiongit (master) => 0.9
2022-11-04 19:52Christian GrothoffStatusinforming => closed
2023-04-13 18:36Florian DoldCategorywallet (TS core) => wallet-core