3

I have a PostgreSQL function A. Many clients will call A:

- client X1 send query 1 "SELECT A();" then
- client X2 send  query 2 "SELECT A();" then
- client X3 send query 3  "SELECT A();" then
...

How to force function A to run sequentially?

Mean that force: query 1 run --> finish or timeout --> query 2 run --> finish or timeout --> query run --> finish or timeout ... (not allow query 1 and query 2 run simultaneously)

0

2 Answers 2

6

Use advisory locks.

The first command in the function body should be (1234 is an exemplary integer constant):

perform pg_advisory_xact_lock(1234);

When two concurrent sessions call the function, one of them will wait until the function in the second one completes. This is a transaction-level advisory lock, automatically released when a transaction terminates.

Alternatively, you can use a session-level advisory lock, which can (should) be manually released:

create function example()
returns void language plpgsql as $$
begin
    perform pg_advisory_lock(1234);
    --
    -- function's commands
    --
    perform pg_advisory_unlock(1234);
end $$;

Any advisory lock obtained in a session is automatically released at the end of the session (if it hasn't been released earlier).

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, PostgreSQL document describe "pg_advisory_xact_lock works the same as pg_advisory_lock, except the lock is automatically released at the end of the current transaction and cannot be released explicitly". Can you explain it more detail: 1. When transaction error, is lock automatically released? 2. When transaction timeout, is lock automatically released?
It's hard to say what transaction error means. When a statement terminates with an error (maybe because of a statement timeout) then the next statements are ignored (if such exist) and the transaction's rollback occurs (so transaction locks are released). If the transaction is cancelled then it is equivalent to rollback. See the edited answer if you're not sure whether to use transaction-level locks.
0

I think the full answer is use pg_advisory_xact_lock + idle_in_transaction_session_timeout in function A.

Query 2 will wait until query 1 is completed (lock auto released) or timeout (session auto killed and lock also auto released).

2 Comments

You don't have to worry about deadlocks as long as you act rationally. Advisory locks never causes deadlocks even if concurrent sessions use multiply nested locks, provided that the order of locks in time is the same in all sessions. To cause a deadlock you have to consciously run concurrent sessions with e.g. locks in reversed order. I don't think there are any reasons to try this.
You may want to set idle_in_transaction_session_timeout for reasons not concerned with advisory locks, e.g. when it happens that connections hang due to communication (net) problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.