proc-retrier.go (3680B)
1 // This file is part of taler-cashless2ecash. 2 // Copyright (C) 2024 Joel Häberli 3 // 4 // taler-cashless2ecash is free software: you can redistribute it and/or modify it 5 // under the terms of the GNU Affero General Public License as published 6 // by the Free Software Foundation, either version 3 of the License, 7 // or (at your option) any later version. 8 // 9 // taler-cashless2ecash is distributed in the hope that it will be useful, but 10 // WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 // Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 // 17 // SPDX-License-Identifier: AGPL3.0-or-later 18 19 package internal_proc 20 21 import ( 22 internal_utils "c2ec/internal/utils" 23 "c2ec/pkg/config" 24 "c2ec/pkg/db" 25 "c2ec/pkg/provider" 26 "context" 27 "errors" 28 "fmt" 29 "time" 30 ) 31 32 const RETRY_CHANNEL_BUFFER_SIZE = 10 33 const PS_RETRY_CHANNEL = "retry" 34 35 func RunRetrier(ctx context.Context, errs chan error) { 36 37 // go RunListener( 38 // ctx, 39 // PS_RETRY_CHANNEL, 40 // retryCallback, 41 // make(chan *Notification, RETRY_CHANNEL_BUFFER_SIZE), 42 // errs, 43 // ) 44 45 go func() { 46 lastlog := time.Now().Add(time.Minute * -3) 47 for { 48 withdrawals, err := db.DB.GetWithdrawalsForConfirmation() 49 time.Sleep(time.Duration(1000 * time.Millisecond)) 50 if err != nil { 51 internal_utils.LogError("proc-retrier", err) 52 errs <- err 53 continue 54 } 55 if lastlog.Before(time.Now().Add(time.Second * -30)) { 56 internal_utils.LogInfo("proc-retrier", fmt.Sprintf("retrier confirming 'selected' withdrawals. found %d ready for confirmation", len(withdrawals))) 57 lastlog = time.Now() 58 } 59 for _, w := range withdrawals { 60 retryOrSkip(w, errs) 61 } 62 } 63 }() 64 } 65 66 // func retryCallback(n *Notification, errs chan error) { 67 68 // withdrawalId, err := strconv.Atoi(n.Payload) 69 // if err != nil { 70 // internal_utils.LogError("proc-retrier", err) 71 // errs <- err 72 // return 73 // } 74 75 // w, err := DB.GetWithdrawalById(withdrawalId) 76 // if err != nil { 77 // internal_utils.LogError("proc-retrier", err) 78 // errs <- err 79 // return 80 // } 81 82 // retryOrSkip(w, errs) 83 // } 84 85 func retryOrSkip(w *db.Withdrawal, errs chan error) { 86 var lastRetryTs int64 = 0 87 if w.LastRetryTs != nil { 88 lastRetryTs = *w.LastRetryTs 89 if internal_utils.ShouldStartRetry(time.Unix(lastRetryTs, 0), int(w.RetryCounter), config.CONFIG.Server.RetryDelayMs) { 90 internal_utils.LogInfo("proc-retrier", "retrying for wopid="+internal_utils.TalerBinaryEncode(w.Wopid)) 91 confirmRetryOrAbort(w, errs) 92 } 93 } else { 94 internal_utils.LogInfo("proc-retrier", "first retry confirming wopid="+internal_utils.TalerBinaryEncode(w.Wopid)) 95 confirmRetryOrAbort(w, errs) 96 } 97 } 98 99 func confirmRetryOrAbort(withdrawal *db.Withdrawal, errs chan error) { 100 101 if withdrawal == nil { 102 err := errors.New("withdrawal was null") 103 internal_utils.LogError("proc-retrier", err) 104 errs <- err 105 return 106 } 107 108 prvdr, err := db.DB.GetProviderByTerminal(withdrawal.TerminalId) 109 if err != nil { 110 internal_utils.LogError("proc-retrier", err) 111 errs <- err 112 return 113 } 114 115 client := provider.PROVIDER_CLIENTS[prvdr.Name] 116 if client == nil { 117 err := fmt.Errorf("the provider client for provider with name=%s is not configured", prvdr.Name) 118 internal_utils.LogError("proc-retrier", err) 119 errs <- err 120 return 121 } 122 transaction, err := client.GetTransaction(*withdrawal.ProviderTransactionId) 123 if err != nil { 124 internal_utils.LogError("proc-retrier", err) 125 errs <- err 126 return 127 } 128 129 finaliseOrSetRetry(transaction, int(withdrawal.WithdrawalRowId), errs) 130 }