146 lines
5.8 KiB
Bash
Executable File
146 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
if [[ "${1:-}" != "--inside" ]]; then
|
|
exec timeout --signal=TERM --kill-after=5s 150s unshare --mount --fork --kill-child=TERM "$0" --inside
|
|
fi
|
|
|
|
name="mysql-pool-idle-test-$$"
|
|
root="/tmp/$name"
|
|
site="$root/site"
|
|
work="$root/work"
|
|
settings="$root/settings.cfg"
|
|
log="$root/service.log"
|
|
socket="$root/run/cli.sock"
|
|
test_user="uce_pool_idle_$$"
|
|
test_database="uce_pool_idle_$$"
|
|
test_password=$(printf '%s' "$name-$(date +%s%N)" | sha256sum | cut -c1-32)
|
|
server_pid=""
|
|
|
|
cleanup() {
|
|
status=$?
|
|
if [[ -n "$server_pid" ]] && kill -0 "$server_pid" 2>/dev/null; then
|
|
kill -TERM "$server_pid" 2>/dev/null || true
|
|
deadline=$((SECONDS + 10))
|
|
while kill -0 "$server_pid" 2>/dev/null && (( SECONDS < deadline )); do sleep 0.05; done
|
|
if kill -0 "$server_pid" 2>/dev/null; then kill -KILL "$server_pid" 2>/dev/null || true; fi
|
|
wait "$server_pid" 2>/dev/null || true
|
|
fi
|
|
mariadb -e "DROP DATABASE IF EXISTS \`$test_database\`; DROP USER IF EXISTS '$test_user'@'127.0.0.1'" >/dev/null 2>&1 || true
|
|
if (( status != 0 )) && [[ -r "$log" ]]; then cat "$log" >&2; fi
|
|
rm -rf "$root"
|
|
return "$status"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
mkdir -p "$site" "$work" "$root/run" "$root/session" "$root/upload"
|
|
cp /etc/uce/settings.cfg "$settings"
|
|
cat >>"$settings" <<CFG
|
|
BIN_DIRECTORY=$work
|
|
PRECOMPILE_FILES_IN=$site
|
|
SITE_DIRECTORY=$site
|
|
FCGI_SOCKET_PATH=$root/run/fastcgi.sock
|
|
FCGI_PORT=
|
|
CLI_SOCKET_PATH=$socket
|
|
CLI_WORKER_COUNT=1
|
|
CLI_WORKER_MAX_REQUESTS=0
|
|
WS_BROKER_SOCKET_PATH=$root/run/ws.sock
|
|
HTTP_PORT=
|
|
HTTP_DOCUMENT_ROOT=$site
|
|
SESSION_PATH=$root/session
|
|
TMP_UPLOAD_PATH=$root/upload
|
|
WASM_CORE_PATH=$(pwd)/bin/wasm/core.wasm
|
|
WORKER_COUNT=1
|
|
PROACTIVE_COMPILE_ENABLED=0
|
|
MYSQL_PERSISTENT_POOL_SIZE=8
|
|
MYSQL_PERSISTENT_POOL_IDLE_TIMEOUT_SECONDS=2
|
|
CFG
|
|
mount --bind "$settings" /etc/uce/settings.cfg
|
|
|
|
mariadb -e "DROP DATABASE IF EXISTS \`$test_database\`; DROP USER IF EXISTS '$test_user'@'127.0.0.1'; CREATE DATABASE \`$test_database\`; CREATE USER '$test_user'@'127.0.0.1' IDENTIFIED BY '$test_password'; GRANT ALL ON \`$test_database\`.* TO '$test_user'@'127.0.0.1'"
|
|
|
|
cat >"$site/database.uce" <<UCE
|
|
CLI(Request& context)
|
|
{
|
|
MySQL* db = mysql_connect("127.0.0.1", "$test_user", "$test_password", "$test_database");
|
|
if(!mysql_connected(db)) { print("connect-failed"); return; }
|
|
String connection_id;
|
|
mysql_query(db, "SELECT CONNECTION_ID() AS id").each([&](DValue row, String key) { connection_id = row["id"].to_string(); });
|
|
String source;
|
|
DValue perf = request_perf();
|
|
perf["mysql_operations"].each([&](DValue operation, String key) {
|
|
if(operation["op"].to_string() == "connect") source = operation["source"].to_string();
|
|
});
|
|
print(perf["worker_pid"].to_string(), "|", connection_id, "|", source);
|
|
mysql_disconnect(db);
|
|
}
|
|
UCE
|
|
printf '%s\n' 'CLI(Request& context) { print(request_perf()["worker_pid"].to_string(), "|plain"); }' >"$site/plain.uce"
|
|
|
|
timeout --signal=TERM --kill-after=5s 120s bin/uce_fastcgi.linux.bin >"$log" 2>&1 &
|
|
server_pid=$!
|
|
deadline=$((SECONDS + 20))
|
|
while [[ ! -S "$socket" ]] && (( SECONDS < deadline )); do sleep 0.05; done
|
|
[[ -S "$socket" ]] || { echo "private UCE CLI socket was not ready" >&2; exit 1; }
|
|
|
|
request() {
|
|
timeout --signal=TERM --kill-after=1s 30s scripts/uce-cli --socket "$socket" "$1"
|
|
}
|
|
|
|
first=$(request /database.uce)
|
|
second=$(request /database.uce)
|
|
IFS='|' read -r first_pid first_id first_source <<<"$first"
|
|
IFS='|' read -r second_pid second_id second_source <<<"$second"
|
|
[[ "$first_source" == "new" && "$second_source" == "worker" ]]
|
|
[[ "$first_pid" == "$second_pid" && "$first_id" == "$second_id" ]]
|
|
|
|
sleep 3
|
|
plain=$(request /plain.uce)
|
|
[[ "$plain" == "$first_pid|plain" ]]
|
|
deadline=$((SECONDS + 5))
|
|
while (( SECONDS < deadline )); do
|
|
connections=$(mariadb --batch --skip-column-names -e "SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE USER='$test_user'")
|
|
[[ "$connections" == "0" ]] && break
|
|
sleep 0.05
|
|
done
|
|
[[ "$connections" == "0" ]] || { echo "expired pooled connection remained after a request boundary" >&2; exit 1; }
|
|
|
|
third=$(request /database.uce)
|
|
IFS='|' read -r third_pid third_id third_source <<<"$third"
|
|
[[ "$third_pid" == "$first_pid" && "$third_source" == "new" && "$third_id" != "$first_id" ]]
|
|
|
|
sleep 3
|
|
plain=$(request /plain.uce)
|
|
[[ "$plain" == "$first_pid|plain" ]]
|
|
deadline=$((SECONDS + 5))
|
|
while (( SECONDS < deadline )); do
|
|
connections=$(mariadb --batch --skip-column-names -e "SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE USER='$test_user'")
|
|
[[ "$connections" == "0" ]] && break
|
|
sleep 0.05
|
|
done
|
|
[[ "$connections" == "0" ]] || { echo "final pooled fixture connection remained after idle eviction" >&2; exit 1; }
|
|
|
|
retained=$(request /database.uce)
|
|
IFS='|' read -r retained_pid retained_id retained_source <<<"$retained"
|
|
[[ "$retained_pid" == "$first_pid" && "$retained_source" == "new" ]]
|
|
connections=$(mariadb --batch --skip-column-names -e "SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE USER='$test_user'")
|
|
[[ "$connections" == "1" ]] || { echo "shutdown fixture connection was not retained in the worker pool" >&2; exit 1; }
|
|
|
|
journal_cursor=$(journalctl -u mariadb.service -n 0 --show-cursor --no-pager | sed -n 's/^-- cursor: //p')
|
|
[[ -n "$journal_cursor" ]] || { echo "could not capture MariaDB journal cursor" >&2; exit 1; }
|
|
kill -TERM "$server_pid"
|
|
deadline=$((SECONDS + 10))
|
|
while kill -0 "$server_pid" 2>/dev/null && (( SECONDS < deadline )); do sleep 0.05; done
|
|
[[ ! -e "/proc/$server_pid" ]] || { echo "private UCE server did not stop cleanly" >&2; exit 1; }
|
|
wait "$server_pid" 2>/dev/null || true
|
|
server_pid=""
|
|
sleep 1
|
|
shutdown_log=$(journalctl -u mariadb.service --after-cursor "$journal_cursor" --no-pager)
|
|
if grep -F "$test_user" <<<"$shutdown_log" | grep -Fq "Aborted connection"; then
|
|
echo "clean UCE shutdown aborted a retained MySQL connection" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Persistent MySQL idle eviction preserved hot reuse, retired expired connections, and closed a retained connection on clean shutdown"
|