MCPcopy Create free account
hub / github.com/devaccuracy/ledgerforge / recordTransactionSingle

Method recordTransactionSingle

transaction.go:783–849  ·  view source on GitHub ↗

recordTransactionSingle preserves the existing direct transaction-processing semantics by running the single-transaction flow under the balance lock.

(ctx context.Context, transaction *model.Transaction)

Source from the content-addressed store, hash-verified

781// recordTransactionSingle preserves the existing direct transaction-processing semantics by
782// running the single-transaction flow under the balance lock.
783func (l *LedgerForge) recordTransactionSingle(ctx context.Context, transaction *model.Transaction) (*model.Transaction, error) {
784 ctx, span := tracer.Start(ctx, "RecordTransaction")
785 defer span.End()
786
787 startTime := time.Now()
788
789 result, err := l.executeWithLock(ctx, transaction, func(ctx context.Context) (*model.Transaction, error) {
790 // Execute pre-transaction hooks
791 if err := l.Hooks.ExecutePreHooks(ctx, transaction.TransactionID, transaction); err != nil {
792 span.RecordError(err)
793 return nil, err
794 }
795
796 // Validate and prepare the transaction, including retrieving source and destination balances
797 transaction, sourceBalance, destinationBalance, err := l.validateAndPrepareTransaction(ctx, transaction)
798 if err != nil {
799 span.RecordError(err)
800 return nil, err
801 }
802
803 // Process the balances by applying the transaction
804 if err := l.processBalances(ctx, transaction, sourceBalance, destinationBalance); err != nil {
805 span.RecordError(err)
806 return nil, err
807 }
808
809 work, skipPersist := l.buildTransactionExecutionWork(ctx, transaction, sourceBalance, destinationBalance)
810 if skipPersist {
811 span.AddEvent("Transaction with zero amount discarded, not persisted", trace.WithAttributes(attribute.String("transaction.id", work.transaction.TransactionID)))
812 return work.transaction, nil
813 }
814
815 work, err = l.persistSingleTransactionExecutionWork(ctx, work)
816 if err != nil {
817 span.RecordError(err)
818 return nil, err
819 }
820
821 l.runTransactionPostCommitWork(ctx, span, []*model.Balance{sourceBalance, destinationBalance}, []queuedBatchPostCommitWork{work})
822
823 span.AddEvent("Transaction processed", trace.WithAttributes(attribute.String("transaction.id", work.transaction.TransactionID)))
824 logrus.Infof("Transaction %s processed successfully", work.transaction.TransactionID)
825 return work.transaction, nil
826 })
827
828 // Record metrics regardless of success or failure.
829 duration := time.Since(startTime).Seconds()
830 status := "error"
831 currency := transaction.Currency
832 if result != nil {
833 status = result.Status
834 currency = result.Currency
835 }
836 metrics.TransactionDuration.Record(ctx, duration,
837 otelmetric.WithAttributes(attribute.String("status", status)),
838 )
839 if err == nil {
840 metrics.TransactionTotal.Add(ctx, 1,

Callers 1

Calls 8

executeWithLockMethod · 0.95
processBalancesMethod · 0.95
ExecutePreHooksMethod · 0.65
StartMethod · 0.45

Tested by

no test coverage detected