#!/bin/bash
set -uo pipefail
#==============================================================#
# File      :   pg-failover-callback
# Desc      :   Patroni event callback script
# Ctime     :   2018-12-06
# Mtime     :   2026-01-14
# Path      :   /pg/bin/pg-failover-callback
# Deps      :   pg-role
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng (rh@vonng.com)
#==============================================================#


#--------------------------------------------------------------#
#                             Usage                            #
#--------------------------------------------------------------#
function usage() {
	cat <<-'EOF'
		NAME
			pg-failover-callback   -- Patroni event callback scripts

		SYNOPSIS
			pg-failover-callback <event> <role> <cluster>

		DESCRIPTION
			This is patroni pg event callback scripts, it will be invoked
			by patroni when certain event happens:
			Available events: on_start|on_stop|on_restart|on_reload|on_role_change
			  - on_start:       PostgreSQL starts
			  - on_stop:        PostgreSQL stops
			  - on_restart:     PostgreSQL restarts (without role change)
			  - on_reload:      Configuration reload triggered
			  - on_role_change: Role promotion or demotion
			Available roles:  primary|replica
			<cluster> will be passed as target cluster name

		EXAMPLES
			pg-failover-callback  on_role_change    master  pg-test
			pg-failover-callback  on_start          replica pg-meta


	EOF
	exit 1
}


#--------------------------------------------------------------#
#                             Path                             #
#--------------------------------------------------------------#
LOGPATH=$(grep -A2 'log:' /etc/patroni/patroni.yml 2>/dev/null | head -n3 | awk '/dir:/ {print $2}')
LOGPATH="${LOGPATH:-/pg/log/patroni}"


#--------------------------------------------------------------#
#                           Handlers                           #
#--------------------------------------------------------------#
function log_callback() {
	printf "[%s][%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "${HOSTNAME}" "$*" >>"${LOGPATH}/callback.log"
}

function on_start_handler() {
	local role="$1"
	local cluster="$2"
	log_callback "on_start: cluster=${cluster} role=${role} started"
}

function on_stop_handler() {
	local role="$1"
	local cluster="$2"
	log_callback "on_stop: cluster=${cluster} role=${role} stopped"
}

function on_restart_handler() {
	local role="$1"
	local cluster="$2"
	log_callback "on_restart: cluster=${cluster} role=${role} restarted"
}

function on_reload_handler() {
	local role="$1"
	local cluster="$2"
	log_callback "on_reload: cluster=${cluster} role=${role} reloaded"
}

function on_role_change_handler() {
	local role="$1"
	local cluster="$2"
	local detect_role
	detect_role=$(/pg/bin/pg-role 2>/dev/null || echo "unknown")
	log_callback "on_role_change: cluster=${cluster} new_role=${role} detect_role=${detect_role}"
	log_callback "on_role_change: executing CHECKPOINT"
	psql -Atqwc 'CHECKPOINT;CHECKPOINT;' 2>/dev/null || true
	log_callback "on_role_change: CHECKPOINT complete"
}


#--------------------------------------------------------------#
#                             Main                             #
#--------------------------------------------------------------#
function main() {
	if [[ $# -lt 3 ]]; then
		echo "[ERROR] pg-failover-callback requires 3 arguments: event role cluster (got $#)" >&2
		exit 1
	fi
	local event="$1"
	local role="$2"
	local cluster="$3"

	# unify role to primary & replica
	case "${role}" in
	primary|p|master|m|leader|l|promoted)
		role="primary"
		;;
	standby|s|replica|r|slave|demoted)
		role="replica"
		;;
	*)
		role="unknown"
		;;
	esac

	# log event to callback.log
	log_callback "${event}: cluster=${cluster} role=${role}"

	# call event handler
	case "${event}" in
	on_start)
		on_start_handler "${role}" "${cluster}"
		;;
	on_stop)
		on_stop_handler "${role}" "${cluster}"
		;;
	on_restart)
		on_restart_handler "${role}" "${cluster}"
		;;
	on_reload)
		on_reload_handler "${role}" "${cluster}"
		;;
	on_role_change)
		on_role_change_handler "${role}" "${cluster}"
		;;
	*)
		log_callback "WARN: unknown event=${event} cluster=${cluster} role=${role}"
		;;
	esac

	exit 0
}

main "$@"
