libpqxx
The C++ client library for PostgreSQL
transactor.hxx
1 /* Transactor framework, a wrapper for safely retryable transactions.
2  *
3  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
4  *
5  * Copyright (c) 2000-2025, Jeroen T. Vermeulen.
6  *
7  * See COPYING for copyright license. If you did not receive a file called
8  * COPYING with this source code, please notify the distributor of this
9  * mistake, or contact the author.
10  */
11 #ifndef PQXX_H_TRANSACTOR
12 #define PQXX_H_TRANSACTOR
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <functional>
19 #include <type_traits>
20 
21 #include "pqxx/connection.hxx"
22 #include "pqxx/transaction.hxx"
23 
24 namespace pqxx
25 {
68 
70 
99 template<typename TRANSACTION_CALLBACK>
100 inline auto perform(TRANSACTION_CALLBACK &&callback, int attempts = 3)
101  -> std::invoke_result_t<TRANSACTION_CALLBACK>
102 {
103  if (attempts <= 0)
104  throw std::invalid_argument{
105  "Zero or negative number of attempts passed to pqxx::perform()."};
106 
107  for (; attempts > 0; --attempts)
108  {
109  try
110  {
111  return std::invoke(callback);
112  }
113  catch (in_doubt_error const &)
114  {
115  // Not sure whether transaction went through or not. The last thing in
116  // the world that we should do now is try again!
117  throw;
118  }
119  catch (statement_completion_unknown const &)
120  {
121  // Not sure whether our last statement succeeded. Don't risk running it
122  // again.
123  throw;
124  }
125  catch (protocol_violation const &)
126  {
127  // This is a subclass of broken_connection, but it's not one where
128  // retrying is likely to do us any good.
129  throw;
130  }
131  catch (broken_connection const &)
132  {
133  // Connection failed. May be worth retrying, if the transactor opens its
134  // own connection.
135  if (attempts <= 1)
136  throw;
137  continue;
138  }
139  catch (transaction_rollback const &)
140  {
141  // Some error that may well be transient, such as serialization failure
142  // or deadlock. Worth retrying.
143  if (attempts <= 1)
144  throw;
145  continue;
146  }
147  }
148  throw pqxx::internal_error{"No outcome reached on perform()."};
149 }
150 } // namespace pqxx
152 #endif
auto perform(TRANSACTION_CALLBACK &&callback, int attempts=3) -> std::invoke_result_t< TRANSACTION_CALLBACK >
Simple way to execute a transaction with automatic retry.
Definition: transactor.hxx:100
Exception class for lost or failed backend connection.
Definition: except.hxx:80
Exception class for micommunication with the server.
Definition: except.hxx:102
The backend saw itself forced to roll back the ongoing transaction.
Definition: except.hxx:177
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
We can't tell whether our last statement succeeded.
Definition: except.hxx:213
Internal error in libpqxx library.
Definition: except.hxx:241
"Help, I don't know whether transaction was committed successfully!"
Definition: except.hxx:164