mem0 / postgres-fuse-wrap
keithproject's picture
fix: keepalive loop β€” re-assert FUSE dirs every 5s during postgres runtime
e8f054f
Raw History Blame Contribute Delete
2.9 kB
#!/bin/bash
# postgres-fuse-wrap: recreate FUSE-volatile dirs then exec postgres as mem0.
# Run by supervisord as root on every (re)start so dirs exist even after the
# ~80s crash-recovery fsync window during which FUSE drops empty dirs.
set -e
PGDATA=/data/pgdata
# Dirs that must exist AND be completely empty (Postgres repopulates them).
for dir in pg_replslot pg_twophase pg_dynshmem pg_notify \
pg_snapshots pg_logical/snapshots pg_logical/mappings; do
mkdir -p "$PGDATA/$dir"
find "$PGDATA/$dir" -mindepth 1 -delete 2>/dev/null || true
done
# Dirs that must exist; contents are written by Postgres β€” only recreate if missing.
for dir in pg_subtrans pg_xact pg_multixact/members pg_multixact/offsets; do
mkdir -p "$PGDATA/$dir"
done
# Dirs that tolerate marker files (Postgres ignores unknown files here)
for dir in pg_commit_ts pg_serial pg_stat pg_stat_tmp; do
mkdir -p "$PGDATA/$dir"
find "$PGDATA/$dir" -mindepth 1 -name '.git' -type d -exec rm -rf {} + 2>/dev/null || true
done
# pg_tblspc must be a symlink to tmpfs β€” FUSE drops real empty dirs
mkdir -p /tmp/pg_tblspc
rm -rf "$PGDATA/pg_tblspc"
ln -sfn /tmp/pg_tblspc "$PGDATA/pg_tblspc"
# Fix ownership: this wrapper runs as root but postgres runs as mem0.
# Only chown the dirs we just created β€” no recursive chown over FUSE (kills mount).
chown mem0:mem0 \
"$PGDATA/pg_subtrans" \
"$PGDATA/pg_xact" \
"$PGDATA/pg_multixact" \
"$PGDATA/pg_multixact/members" \
"$PGDATA/pg_multixact/offsets" \
"$PGDATA/pg_snapshots" \
"$PGDATA/pg_logical" \
"$PGDATA/pg_logical/snapshots" \
"$PGDATA/pg_logical/mappings" \
"$PGDATA/pg_commit_ts" \
"$PGDATA/pg_serial" \
"$PGDATA/pg_stat" \
"$PGDATA/pg_stat_tmp" \
"$PGDATA/pg_replslot" \
"$PGDATA/pg_twophase" \
"$PGDATA/pg_dynshmem" \
"$PGDATA/pg_notify" \
2>/dev/null || true
chown -h mem0:mem0 "$PGDATA/pg_tblspc"
# Background loop: FUSE can drop empty dirs at any time during runtime, not
# just at startup. Re-assert critical dirs every 5s while postgres is alive.
fuse_keepalive() {
while true; do
sleep 5
for dir in pg_replslot pg_twophase pg_dynshmem pg_notify \
pg_snapshots pg_logical/snapshots pg_logical/mappings; do
if [ ! -d "$PGDATA/$dir" ]; then
mkdir -p "$PGDATA/$dir" 2>/dev/null && \
chown mem0:mem0 "$PGDATA/$dir" 2>/dev/null || true
fi
done
if [ ! -L "$PGDATA/pg_tblspc" ]; then
rm -rf "$PGDATA/pg_tblspc"
ln -sfn /tmp/pg_tblspc "$PGDATA/pg_tblspc" 2>/dev/null
chown -h mem0:mem0 "$PGDATA/pg_tblspc" 2>/dev/null || true
fi
done
}
fuse_keepalive &
KEEPALIVE_PID=$!
# Drop to mem0 and exec postgres.
# Note: exec replaces this shell, so trap cleanup of keepalive on exit.
trap "kill $KEEPALIVE_PID 2>/dev/null" EXIT
exec gosu mem0 /usr/lib/postgresql/15/bin/postgres \
-D "$PGDATA" \
-c config_file="$PGDATA/postgresql.conf"