Skip to content

chore(deploy): add psycopg3 cutover + rollback script - #213

Merged
jphein merged 1 commit into
mainfrom
chore/deploy-psycopg3-cutover-script
May 26, 2026
Merged

chore(deploy): add psycopg3 cutover + rollback script#213
jphein merged 1 commit into
mainfrom
chore/deploy-psycopg3-cutover-script

Conversation

@jphein

@jphein jphein commented May 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds scripts/deploy-psycopg3-cutover.sh — orchestrates cutting both KG worker pools (katana kg-2080, familiar kg-p102) over to the psycopg3 + AsyncConnectionPool branch landed in perf(kg-extract): migrate KG triple worker to psycopg3 AsyncConnectionPool #208.
  • Captures baseline rate from ~/.local/bin/kg-backfill-per-pool.sh (per-pool JSON: total_rate, katana_rate, famili_rate, eta_h).
  • Auto-rollback if post-cutover total_rate drops below 85% of baseline for 2 consecutive samples.
  • DRY_RUN=1 mode plans without acting; ROLLBACK_TO=<sha> allows explicit rollback target instead of auto-captured pre-pull HEAD.

Why

Tonight's deploy needs a repeatable, observable cutover with a safety net — manual SSH + restart sequence is error-prone given the dual-host setup. This script is the cleaner standalone follow-up to #208 (which migrated the worker code).

Test plan

  • Dry-run on familiar: DRY_RUN=1 scripts/deploy-psycopg3-cutover.sh <current-sha> → confirms plan output without executing
  • Actual cutover after chore(deps): refresh pyproject lower bounds + dependabot config #207 lands: scripts/deploy-psycopg3-cutover.sh <new-sha> → both pools pick up new code, throughput stable
  • Manual regression test: artificially throttle one pool to verify rollback triggers correctly

🤖 Generated with Claude Code

scripts/deploy-psycopg3-cutover.sh stages the KG extractor cutover from
psycopg2 to Morpheus's psycopg3 + AsyncConnectionPool branch:

  1. Capture pre-cutover SHAs on katana + familiar (rollback anchors)
  2. Sample N baseline rates via ~/.local/bin/kg-backfill-per-pool.sh
  3. Pull NEW_SHA + reinstall extras on both hosts
  4. Restart worker tmux sessions (kg-2080 on katana, kg-p102 on familiar)
  5. Sample N post-cutover rates; rollback if rate < BASELINE * 0.85 for
     ROLLBACK_CONFIRM consecutive samples
  6. Either announce success or git-reset-hard + reinstall + restart

Defaults: 3 baseline samples + 5 post samples, 20 s apart, 0.85 threshold,
2 consecutive bad samples to trip rollback. All overridable via env.

DRY_RUN=1 prints every state-changing command instead of executing it.
Smoke-tested both happy path and forced-rollback path against the live
queue (50.1/min baseline observed). bash -n + shellcheck clean.

141 lines, single bash script — no new deps.
Copilot AI review requested due to automatic review settings May 26, 2026 11:06
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust deployment and rollback orchestration script designed to manage the transition of KG worker pools to the new psycopg3 implementation. By automating the code deployment, dependency installation, and service restarts across multiple hosts, the script minimizes manual intervention and provides a safety net to automatically revert changes if performance regressions are detected.

Highlights

  • Deployment Automation: Introduced a new bash script, scripts/deploy-psycopg3-cutover.sh, to automate the migration of KG worker pools to the psycopg3 branch.
  • Safety Mechanisms: Implemented automated health monitoring that compares post-deployment throughput against a baseline, triggering an automatic rollback if performance drops below 85%.
  • Operational Flexibility: Added support for dry-run mode and explicit rollback targets to provide better control and observability during the deployment process.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a deployment and rollback script (scripts/deploy-psycopg3-cutover.sh) designed to manage the cutover of worker pools to psycopg3. The script monitors throughput metrics and automatically rolls back to pre-cutover SHAs if performance drops below a specified threshold. The review feedback highlights several instances of direct shell variable interpolation inside inline Python scripts, which can lead to syntax errors, and suggests passing these variables as command-line arguments instead. Additionally, the reviewer points out that relying on tmux send-keys ... Up Enter to restart worker processes is fragile and recommends using explicit startup commands or systemd services.

for ((i=1; i<=n; i++)); do
rate=$(sample_total_rate)
printf ' sample %d/%d: %s/min\n' "$i" "$n" "$rate" >&2
sum=$(python3 -c "print($sum + $rate)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Interpolating shell variables directly into the inline Python script string can lead to syntax errors if the variables are empty or contain unexpected characters. It is safer to pass them as command-line arguments to Python and access them via sys.argv.

Suggested change
sum=$(python3 -c "print($sum + $rate)")
sum=$(python3 -c "import sys; print(float(sys.argv[1]) + float(sys.argv[2]))" "$sum" "$rate")

sum=$(python3 -c "print($sum + $rate)")
[ "$i" -lt "$n" ] && sleep "$SAMPLE_INTERVAL"
done
python3 -c "print(round($sum / $n, 1))"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Pass $sum and $n as arguments to Python to avoid syntax errors from direct shell variable interpolation.

Suggested change
python3 -c "print(round($sum / $n, 1))"
python3 -c "import sys; print(round(float(sys.argv[1]) / float(sys.argv[2]), 1))" "$sum" "$n"

step "2/6 baseline throughput ($BASELINE_SAMPLES samples × ${SAMPLE_INTERVAL}s)"
BASELINE=$(mean_rate "$BASELINE_SAMPLES")
ok "baseline total_rate = ${BASELINE}/min"
THRESHOLD=$(python3 -c "print(round($BASELINE * $REGRESSION_FACTOR, 1))")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Pass $BASELINE and $REGRESSION_FACTOR as arguments to Python to prevent syntax errors if the variables are empty or malformed.

Suggested change
THRESHOLD=$(python3 -c "print(round($BASELINE * $REGRESSION_FACTOR, 1))")
THRESHOLD=$(python3 -c "import sys; print(round(float(sys.argv[1]) * float(sys.argv[2]), 1))" "$BASELINE" "$REGRESSION_FACTOR")

Comment on lines +104 to +106
run "tmux send-keys -t kg-2080 C-c"
run "sleep 3"
run "tmux send-keys -t kg-2080 Up Enter"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Relying on tmux send-keys ... Up Enter to restart the worker is highly fragile. If any other command was run in that tmux pane (e.g., during manual debugging or log viewing), Up Enter will execute that command instead of the worker. Consider explicitly running the startup command or utilizing a systemd service (like the one defined in deploy/systemd/kg-extract.env.example) for reliable process management.

for ((s=1; s<=POST_SAMPLES; s++)); do
rate=$(sample_total_rate)
printf ' sample %d/%d: %s/min (threshold %s)\n' "$s" "$POST_SAMPLES" "$rate" "$THRESHOLD"
if python3 -c "import sys; sys.exit(0 if $rate < $THRESHOLD else 1)"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly interpolating $rate and $THRESHOLD into the Python command string is prone to syntax errors if either variable is empty or malformed. Passing them as arguments is much more robust.

Suggested change
if python3 -c "import sys; sys.exit(0 if $rate < $THRESHOLD else 1)"; then
if python3 -c "import sys; sys.exit(0 if float(sys.argv[1]) < float(sys.argv[2]) else 1)" "$rate" "$THRESHOLD"; then

@jphein
jphein merged commit b4b1419 into main May 26, 2026
@jphein
jphein deleted the chore/deploy-psycopg3-cutover-script branch May 26, 2026 11:11
@jphein
jphein removed the request for review from Copilot May 26, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant