If a system failure (such as server failure) occurs in an application that uses distributed transactions (such as .NET TransactionScope), then transactions may be changed to the in-doubt state.
At that point, resources accessed by the transaction will be locked, and rendered unusable by other transactions.
The following describes how to check for in-doubt transactions, and how to resolve them.
How to check for in-doubt transactions
The following shows how to check for them:
An in-doubt transaction will have occurred if a message similar to the one below is output to the log when the server is restarted.
LOG: Restoring prepared transaction 2103.
Refer to system view pg_prepared_xacts to obtain information about the prepared transaction.
If the transaction identifier of the prepared transaction in the list (in the transaction column of pg_prepared_xacts) is the same as the identifier of the in-doubt transaction obtained from the log output when the server was restarted, then that row is the information about the in-doubt transaction.
postgres=# select * from pg_prepared_xacts; transaction | gid | prepared | owner | database -------------+-----------+------------+----------+---------- 2103 | 374cc221-f6dc-4b73-9d62-d4fec9b430cd | 2022-03-06 16:28:48.471+08 | postgres | postgres (1 row)
Information about the in-doubt transaction is output to the row with the transaction ID 2103 in the transaction column.
If there are no clients connected and there is a prepared transaction in pg_prepared_xacts, then you can determine that the transaction is in the in-doubt state.
If at least one client is connected and there is a prepared transaction in pg_prepared_xacts, you cannot determine whether there is a transaction in the in-doubt state. In this case, use the following query to determine the in-doubt transaction from the acquired database name, user name, the time PREPARE TRANSACTION was executed, and the information about the table name accessed.
select gid,x.database,owner,prepared,l.relation::regclass as relation from pg_prepared_xacts x left join pg_locks l on l.virtualtransaction = '-1/'||x.transaction and l.locktype='relation';
If it still cannot be determined from this information, wait a few moments and then check pg_prepared_xacts again.
If there is a transaction that has continued since the last time you checked, then it is likely that it is the one in the in-doubt state.
Point
As you can see from the explanations in this section, there is no one way to definitively determine in-doubt transactions.
Consider collecting other supplementary information (for example, logging on the client) or performing other operations (for example, allocating database users per job).
How to resolve in-doubt transactions
From the system view pg_prepared_xacts mentioned above, obtain the global transaction identifier (in the gid column of pg_prepared_xacts) for the in-doubt transaction, and issue either a ROLLBACK PREPARED statement or COMMIT PREPARED statement to resolve the in-doubt transaction.
Example
Rolling back in-doubt transactions
postgres=# rollback prepared '374cc221-f6dc-4b73-9d62-d4fec9b430cd';
ROLLBACK PREPARED
Committing in-doubt transactions
postgres=# commit prepared '374cc221-f6dc-4b73-9d62-d4fec9b430cd';
COMMIT PREPARED