Graças ao comentário de @sudo acima, se eu movi as declarações assim:
BEGIN;
SELECT pg_advisory_xact_lock(2142616474639426746);
CREATE OR REPLACE FUNCTION my_function() ....
--the whole function definition is wrapped by an advisory lock
SELECT * FROM my_function();
COMMIT;
então parece evitar o problema, eu usei dados grandes (na verdade, fingi com loops repetidos pelos mesmos dados). Observe que pode não ser a maneira mais eficiente de fazer esse tipo de coisa, mas funciona. O problema com a tentativa dada na pergunta era que o bloqueio provavelmente estava limitado apenas à transação em que foi definido e, portanto, a criação da função ainda estava fora de seu escopo, ou seja, não bloqueada, portanto, o conflito estava aparecendo. Mas, tudo parece bem e elegante agora.