exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit b9899d4cafa8e3a16f235ecad2816f7c397386a1
parent 8fa1244b92d3f779b67809713fa991f56d19ce78
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  6 Aug 2026 22:42:23 +0200

retry KYC rule evaluation on serialization failure

Diffstat:
Msrc/exchange/taler-exchange-aggregator.c | 57++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c @@ -807,6 +807,40 @@ trigger_wire_transfer (struct AggregationUnit *au) } +/** + * A step of #evaluate_rules() failed. If that was a serialization failure + * and we still have retries left, roll the transaction back and evaluate the + * rules again from the top; the KYC measure, the transient's requirement_row + * and the append-only deferral record are written in one transaction and + * nothing else ever rescans transients, so dropping them here loses them for + * good. + * + * @param[in,out] au aggregation we are working on + * @param qs status that made the caller stop + * @return true if a retry was scheduled and the caller must return at once + */ +static bool +retry_rule_evaluation (struct AggregationUnit *au, + enum GNUNET_DB_QueryStatus qs) +{ + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + return false; + if (au->retries++ >= MAX_RETRIES) + return false; + TALER_EXCHANGEDB_rollback (pg); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Serialization failure evaluating KYC rules, trying again!\n"); + au->ru = TALER_EXCHANGEDB_begin_rule_update ( + pg, + &attribute_key, + &au->h_normalized_payto, + false, /* aggregation does not apply to wallets */ + &evaluate_rules, + au); + return (NULL != au->ru); +} + + static void evaluate_rules ( struct AggregationUnit *au, @@ -869,6 +903,9 @@ evaluate_rules ( { TALER_KYCLOGIC_rules_free (lrs); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (retry_rule_evaluation (au, + qs)) + return; cleanup_and_next (au); return; } @@ -906,6 +943,10 @@ evaluate_rules ( "Failed to persist KYC requirement `%s' in DB!\n", TALER_KYCLOGIC_rule2s (requirement)); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + TALER_KYCLOGIC_rules_free (lrs); + if (retry_rule_evaluation (au, + qs)) + return; if (GNUNET_DB_STATUS_HARD_ERROR == qs) global_ret = EXIT_FAILURE; cleanup_and_next (au); @@ -928,6 +969,9 @@ evaluate_rules ( GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to persist updated transient in in DB!\n"); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (retry_rule_evaluation (au, + qs)) + return; if (GNUNET_DB_STATUS_HARD_ERROR == qs) global_ret = EXIT_FAILURE; cleanup_and_next (au); @@ -951,6 +995,9 @@ evaluate_rules ( GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to persist deferral reason in DB!\n"); GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (retry_rule_evaluation (au, + qs)) + return; if (GNUNET_DB_STATUS_HARD_ERROR == qs) global_ret = EXIT_FAILURE; cleanup_and_next (au); @@ -971,7 +1018,15 @@ evaluate_rules ( } /* First commit, turns the rollback in cleanup into a NOP! */ - commit_or_warn (); + qs = commit_or_warn (); + if (0 > qs) + { + if (retry_rule_evaluation (au, + qs)) + return; + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + global_ret = EXIT_FAILURE; + } cleanup_and_next (au); }