#!/usr/bin/env bash set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" api_port="${TIKU_API_PORT:-5091}" mode="${TIKU_MODE:-mixed}" rate="${TIKU_RATE:-100}" duration="${TIKU_DURATION:-30s}" tenant_code="${TIKU_TENANT_CODE:-demo-crm-school}" redis_container="${TIKU_REDIS_CONTAINER:-tiku-redis}" database_name="${TIKU_DATABASE_NAME:-tiku}" run_stamp="$(date +%Y%m%d-%H%M%S)" result_dir="${repo_root}/artifacts/performance/${run_stamp}-${mode}-${rate}rps" api_pid="" cleanup() { if [[ -n "${api_pid}" ]] && kill -0 "${api_pid}" 2>/dev/null; then kill "${api_pid}" 2>/dev/null || true wait "${api_pid}" 2>/dev/null || true fi api_pid="" } trap cleanup EXIT INT TERM mkdir -p "${result_dir}" if ! command -v docker >/dev/null 2>&1; then echo "docker is required for the Redis readiness check" >&2 exit 1 fi if ! docker inspect "${redis_container}" >/dev/null 2>&1; then echo "Redis container '${redis_container}' does not exist" >&2 exit 1 fi if [[ "$(docker inspect -f '{{.State.Running}}' "${redis_container}")" != "true" ]]; then echo "Redis container '${redis_container}' is not running" >&2 exit 1 fi docker exec "${redis_container}" redis-cli ping | grep -qx PONG if ! command -v psql >/dev/null 2>&1; then echo "psql is required to capture PostgreSQL metrics" >&2 exit 1 fi psql -d "${database_name}" -Atqc 'select 1' | grep -qx 1 ( cd "${repo_root}" dotnet build TIKU-BACKEND.slnx -c Release --no-restore ) host_url="http://127.0.0.1:${api_port}" load_url="${host_url}" ( cd "${repo_root}" exec env \ ASPNETCORE_ENVIRONMENT=Development \ ASPNETCORE_URLS="http://0.0.0.0:${api_port}" \ ConnectionStrings__Redis=localhost:6379 \ RateLimiting__Enabled=false \ BackgroundProcessing__Enabled=false \ Serilog__MinimumLevel__Default=Warning \ dotnet run --project Tiku.Api -c Release --no-build --no-launch-profile ) >"${result_dir}/api.log" 2>&1 & api_pid=$! ready_body="" for _ in $(seq 1 60); do if ready_body="$(curl -fsS "${host_url}/api/health/ready" 2>/dev/null)"; then break fi if ! kill -0 "${api_pid}" 2>/dev/null; then echo "Tiku.Api stopped during startup; see ${result_dir}/api.log" >&2 exit 1 fi sleep 1 done if [[ -z "${ready_body}" ]]; then echo "Tiku.Api did not become ready; see ${result_dir}/api.log" >&2 exit 1 fi printf '%s\n' "${ready_body}" >"${result_dir}/readiness.json" if ! printf '%s' "${ready_body}" | grep -q '"status":"ready"'; then echo "PostgreSQL or Redis is not ready: ${ready_body}" >&2 exit 1 fi capture_dependencies() { local suffix="$1" psql -d "${database_name}" -P pager=off -c \ "select datname, numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched from pg_stat_database where datname = current_database();" \ >"${result_dir}/postgres-${suffix}.txt" docker exec "${redis_container}" redis-cli INFO stats \ >"${result_dir}/redis-${suffix}.txt" } capture_dependencies before { sw_vers printf 'logical_cpu: ' sysctl -n hw.logicalcpu printf 'memory_bytes: ' sysctl -n hw.memsize dotnet --info } >"${result_dir}/host.txt" set +e if command -v k6 >/dev/null 2>&1; then load_url="${host_url}" k6 run \ --summary-export "${result_dir}/summary.json" \ -e "TIKU_BASE_URL=${load_url}" \ -e "TIKU_HOST_HEADER=localhost:${api_port}" \ -e "TIKU_TENANT_CODE=${tenant_code}" \ -e "TIKU_MODE=${mode}" \ -e "TIKU_RATE=${rate}" \ -e "TIKU_DURATION=${duration}" \ "${repo_root}/tools/performance/tiku-api.js" \ | tee "${result_dir}/k6.txt" k6_exit=${PIPESTATUS[0]} else load_url="http://host.docker.internal:${api_port}" docker run --rm \ -v "${repo_root}:/work:ro" \ -v "${result_dir}:/results" \ grafana/k6:latest \ run \ --summary-export /results/summary.json \ -e "TIKU_BASE_URL=${load_url}" \ -e "TIKU_HOST_HEADER=localhost:${api_port}" \ -e "TIKU_TENANT_CODE=${tenant_code}" \ -e "TIKU_MODE=${mode}" \ -e "TIKU_RATE=${rate}" \ -e "TIKU_DURATION=${duration}" \ /work/tools/performance/tiku-api.js \ | tee "${result_dir}/k6.txt" k6_exit=${PIPESTATUS[0]} fi set -e cleanup capture_dependencies after printf 'mode=%s\nrate=%s\nduration=%s\ntenant=%s\nk6_exit=%s\n' \ "${mode}" "${rate}" "${duration}" "${tenant_code}" "${k6_exit}" \ >"${result_dir}/run.env" echo "Results: ${result_dir}" exit "${k6_exit}"