#!/bin/bash
# Simulasi dua pekerja memanen antrian transfer yang sama.
# Pekerja A mengambil dua pekerjaan dan menahan transaksinya terbuka;
# pekerja B menjalankan perintah yang sama dan mendapat pekerjaan yang bebas.

: "${PGDATABASE:=latihan}"
export PGDATABASE

TMPD=$(mktemp -d)
mkfifo "$TMPD/komando.fifo"

# Pekerja A: sesi psql yang tetap hidup, perintah dikirim lewat fifo
PGAPPNAME=pekerja-a psql -X < "$TMPD/komando.fifo" > "$TMPD/a.log" 2>&1 &
SESIA=$!
exec 3>"$TMPD/komando.fifo"

printf "BEGIN;
WITH diambil AS (
    SELECT id
    FROM antrian_transfer
    WHERE status = 'menunggu'
    ORDER BY id
    LIMIT 2
    FOR UPDATE SKIP LOCKED
)
UPDATE antrian_transfer a
SET status = 'diproses'
FROM diambil d
WHERE a.id = d.id
RETURNING a.id, a.rekening_id, a.jumlah, a.status;
" >&3

# Tunggu sampai pekerja A memegang kunci dua baris pertama
for i in $(seq 1 100); do
  n=$(psql -X -tA -c "SELECT count(*) FROM pg_stat_activity
                      WHERE datname = current_database()
                        AND application_name = 'pekerja-a'
                        AND state = 'idle in transaction'")
  [ "$n" = "1" ] && break
  sleep 0.05
done

# Pekerja B: perintah yang sama, dijalankan saat baris 1-2 masih terkunci pekerja A
PGAPPNAME=pekerja-b psql -X > "$TMPD/b.log" 2>&1 <<'PEKERJA'
BEGIN;
WITH diambil AS (
    SELECT id
    FROM antrian_transfer
    WHERE status = 'menunggu'
    ORDER BY id
    LIMIT 2
    FOR UPDATE SKIP LOCKED
)
UPDATE antrian_transfer a
SET status = 'diproses'
FROM diambil d
WHERE a.id = d.id
RETURNING a.id, a.rekening_id, a.jumlah, a.status;
COMMIT;
PEKERJA

# Pekerja A menutup transaksinya
printf 'COMMIT;\n' >&3
exec 3>&-
wait $SESIA

echo "== Pekerja A (transaksi masih terbuka saat B berjalan) =="
cat "$TMPD/a.log"
echo
echo "== Pekerja B (baris 1-2 dilewati karena terkunci) =="
cat "$TMPD/b.log"
echo
echo "== Isi antrian setelah kedua pekerja commit =="
psql -X -c "SELECT id, rekening_id, jumlah, status FROM antrian_transfer ORDER BY id;"

rm -rf "$TMPD"
