From cc47bdcb0a200d645d21f2d51be9fddc566f0871 Mon Sep 17 00:00:00 2001
From: Ramkumar Ethiraj <64294490+rmkr-dev@users.noreply.github.com>
Date: Sat, 31 Oct 2026 05:09:28 +0000
Subject: [PATCH 1/2] Add HikariCP connection pool guardrails skill
---
skillbook/skills.json | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/skillbook/skills.json b/skillbook/skills.json
index 54b149b..5ab3c83 100644
--- a/skillbook/skills.json
+++ b/skillbook/skills.json
@@ -877,6 +877,27 @@
],
"formatNotes": "All three. Copilot: path-scoped `.github/instructions/rulesets.instructions.md` with applyTo for `.github/rulesets/**` and `.github/workflows/**`, or `.github/skills/github-rulesets-merge-queue-guardrails/SKILL.md`; one always-on line in `.github/copilot-instructions.md` (\"required workflows run unfiltered, listen to merge_group, and end in a ci-ok gate job\"). Claude Code: `.claude/skills/github-rulesets-merge-queue-guardrails/SKILL.md`, plus a CLAUDE.md line naming the gate job and where rulesets live. Codex: a \"Branch rules\" section in root `AGENTS.md` (or the same SKILL.md under `.agents/skills/`). Pair with gha-devsecops-pipeline for workflow permissions, dependency-update-automation-guardrails for bot auto-merge, and secure-pr-review-guardrails for what reviewers check. This skill owns what may reach main and how.",
"body": "# Skill: GitHub Rulesets and Merge Queue as Code\n\n## Goal\nThe rules that protect `main` and release tags live in the repository as reviewed files, not as clicks in Settings. Every merge passes the same named checks, a merge queue tests the exact commit that lands when the branch is busy, bypass is rare and visible, and a scheduled job notices when someone changes a rule by hand.\n\n## When to apply\n- Moving a repository or organization from classic branch protection to rulesets\n- Adding a merge queue, or a team keeps hitting \"branch is out of date\" and re-running CI after every merge\n- Required checks are named by hand, some PRs hang on \"Expected — Waiting for status to be reported\", or a workflow uses path filters and is also required\n- Someone asks for a bypass, an admin override, or a bot that merges without review\n- Release tags (`v*`) can be moved, deleted, or created by anyone with write access\n\n## Rulesets in one table\n| Concern | Classic branch protection | Rulesets |\n| --- | --- | --- |\n| Scope | one pattern per rule, repo only | repo, organization, or enterprise; `~DEFAULT_BRANCH`, `~ALL`, fnmatch include and exclude |\n| Layering | one rule wins per branch | every matching ruleset applies; the strictest setting of each rule wins |\n| Targets | branches | `branch`, `tag`, and `push` (file path, size, extension) rulesets |\n| Trial run | none | `enforcement: evaluate` (Enterprise) reports what would fail without blocking |\n| Bypass | admins, plus a few allow lists | explicit `bypass_actors` with `always`, `pull_request`, or `exempt` mode |\n| As code | REST only | REST and `gh ruleset`, JSON import and export in the UI, Terraform `github_repository_ruleset` |\n| Merge queue | separate setting | `merge_queue` rule (repository-level rulesets only) |\n\nClassic protection and rulesets both apply when they overlap, so migrate one branch at a time and delete the classic rule only after the ruleset is active and verified.\n\n## Baseline rules\n1. **Keep the source of truth in the repo.** Store each ruleset as JSON under `.github/rulesets/` (or as Terraform with the `integrations/github` provider for many repos). Apply with `gh api --method PUT repos/{owner}/{repo}/rulesets/{id} --input file.json` (POST for the first create), from a reviewed PR, by a person or a workflow that holds an admin-scoped token. Never apply from an unreviewed branch.\n2. **One default-branch ruleset, one tag ruleset, layered org rules.** Default branch: `deletion`, `non_fast_forward`, `pull_request`, `required_status_checks`, and optionally `required_linear_history`, `required_signatures`, `merge_queue`, `code_scanning`. Tags matching `v*`: `creation`, `update`, and `deletion` restricted to the release workflow or a release team. Put org-wide minimums (no force push, no deletion of `main`) in an organization ruleset and repo specifics in the repo.\n3. **Pull request rule with real review settings.** `required_approving_review_count` of 1 or more, `dismiss_stale_reviews_on_push: true`, `require_code_owner_review: true` where CODEOWNERS exists, `require_last_push_approval: true` so the last pusher cannot self-approve, `required_review_thread_resolution: true`, and `allowed_merge_methods` matching the repo's settings.\n4. **Required checks are named precisely.** The context is the check run name, which for Actions is the job `name:` (matrix jobs add the matrix values, e.g. `test (21)`). Pin the source with `integration_id` (15368 is GitHub Actions) so another app or a commit status with the same name cannot satisfy it. Give jobs stable, unique names and never rename a required job in the same PR that changes the ruleset.\n5. **Required workflows must always report.** A workflow with `paths:` or `branches:` filters that does not run leaves its required check pending forever. Keep the trigger unfiltered and skip inside: a small `changes` job (e.g. `dorny/paths-filter` pinned by SHA) plus a final gate job such as `ci-ok` with `if: always()` that fails when any needed job failed or was cancelled. Require only the gate job.\n6. **Merge queue for busy branches.** Add `merge_group:` to every workflow that produces a required check, beside `pull_request:`, or the queue waits until timeout. Start with `grouping_strategy: ALLGREEN`, `max_entries_to_build` around 5, `min_entries_to_merge: 1`, `check_response_timeout_minutes` a little above your slowest required job, and the same `merge_method` as the repo. Queue branches are named `gh-readonly-queue//...`; do not deploy from them and do not run secrets-heavy jobs only because of `merge_group`. With a queue, turn off \"require branches to be up to date\" (`strict_required_status_checks_policy`), because the queue already tests the merged result.\n7. **Bypass is an exception with a name.** Prefer no bypass actors. If needed, use a team or a specific GitHub App with `bypass_mode: pull_request`, so bypass happens in the open on a PR, never `always` for humans. Keep `exempt` for automation that genuinely must skip rules, and note that exempt actors leave no bypass entry. Bypass has been reported not to apply to auto-merge completion and queue entry, so a bot that needs it should call the merge endpoint directly rather than relying on `--auto`.\n8. **Bots go through the gate too.** Dependency bots and release bots open PRs and wait for the same checks. The default `GITHUB_TOKEN` cannot add a PR to a merge queue and its pushes do not trigger new workflow runs; use a GitHub App token with the narrowest permissions for automation that must enqueue or push.\n9. **Trial before enforcement.** On Enterprise, create new rulesets with `enforcement: evaluate` for a week and read Rule Insights. Elsewhere, enable on a low-traffic repo first, then roll out. Use `gh ruleset check main` to see which rules apply to a branch and `gh ruleset view` to read the live result.\n10. **Detect drift.** A scheduled workflow (weekly, working hours) reads the live rulesets with a token that can see bypass actors, normalizes the JSON (drop `id`, `node_id`, `_links`, timestamps, `current_user_can_bypass`), diffs it against `.github/rulesets/`, and opens an issue on any difference. It reports; it does not silently re-apply.\n11. **Changes are reviewed like code.** CODEOWNERS on `.github/rulesets/` and the apply and drift workflows; the PR description says which rule changes and why; loosening a rule (fewer reviewers, new bypass actor, removed check) needs a security or platform owner's approval.\n\n## Workflow\n1. **Export.** `gh api repos/{owner}/{repo}/rulesets` and each `rulesets/{id}`, plus classic protection from `branches/main/protection`. Save normalized JSON as the starting point.\n2. **Inventory checks.** List the check runs on a recent green PR (`gh pr checks `); match each to a job name and app; mark which ones are path-filtered.\n3. **Fix the workflows first.** Unfiltered triggers, a gate job, `merge_group:` triggers, stable job names. Merge that before touching rules.\n4. **Write the rulesets** (rules 2 to 7) as files, review, then apply.\n5. **Migrate.** Activate the ruleset, confirm with `gh ruleset check`, then delete the overlapping classic protection.\n6. **Prove it.** A PR with a failing test cannot merge; a PR without approval cannot merge; a direct push and a force push to `main` are rejected; a non-release actor cannot create a `v*` tag; with a queue, two PRs merge in order and a failing one is removed from the queue.\n7. **Turn on drift detection** and document the apply process in `CONTRIBUTING.md`.\n\n## Review checklist\n- [ ] Rulesets live as JSON or Terraform in the repo, applied from reviewed changes\n- [ ] Default branch blocks deletion and force push and requires PRs with stale-review dismissal, code owners, last-push approval, and thread resolution\n- [ ] Required checks use exact job names and `integration_id`; one always-running gate job is required\n- [ ] No required check comes from a path-filtered or branch-filtered workflow\n- [ ] Every required workflow listens to `merge_group`; queue settings and timeout fit CI duration\n- [ ] Release tags are protected from creation, update, and deletion except by the release path\n- [ ] Bypass actors are few, named, and `pull_request` mode for humans\n- [ ] Automation that enqueues or pushes uses an App token, not `GITHUB_TOKEN`\n- [ ] Classic protection removed only after the ruleset was verified\n- [ ] A scheduled drift check opens an issue on differences\n- [ ] CODEOWNERS covers the ruleset files and workflows\n\n## Copy-ready SKILL.md stub\n```markdown\n---\nname: github-rulesets-merge-queue-guardrails\ndescription: Use when creating or changing GitHub branch or tag protection, rulesets, required status checks, or a merge queue: rulesets stored as JSON or Terraform in the repo, PR reviews with stale-dismissal, code owners, and last-push approval, required checks pinned by exact job name and app, an always-running gate job instead of path-filtered required workflows, merge_group triggers, protected release tags, minimal pull_request-mode bypass, App tokens for automation, and scheduled drift detection.\n---\n\nFollow GitHub Rulesets and Merge Queue as Code: keep rulesets as reviewed files in the repo and apply them only from merged changes. Protect the default branch from deletion and force push, require PRs with stale-review dismissal, code owner review, last-push approval, and resolved threads. Require exact check names with integration_id, and require one always-running gate job rather than path-filtered workflows. Add merge_group triggers to every required workflow before enabling the merge queue, and drop strict up-to-date checks once the queue is on. Protect v* tags so only the release path can create, move, or delete them. Keep bypass actors minimal and in pull_request mode for humans. Use GitHub App tokens for automation that must enqueue or push. Migrate from classic protection one branch at a time, prove the rules with failing PRs and rejected pushes, and run a scheduled drift check that opens an issue.\n```\n"
+ },
+ {
+ "id": "hikari-connection-pool-guardrails",
+ "title": "HikariCP Connection Pool Guardrails for Spring Boot",
+ "whenToUse": "Configuring or reviewing database connection pooling in a Spring Boot service on Kubernetes — a fixed, small HikariCP pool sized from database capacity divided across all replicas at HPA max, connection timeout well under the request timeout, maxLifetime and keepalive below database and load balancer idle limits, short transactions with open-in-view off, statement timeouts on the database side, leak detection in lower environments, PgBouncer transaction-mode settings, virtual-thread contention, pool metrics with alerts on pending threads and timeouts, and graceful shutdown.",
+ "tools": [
+ "copilot",
+ "claude-code",
+ "codex"
+ ],
+ "tags": [
+ "java",
+ "spring-boot",
+ "hikaricp",
+ "postgresql",
+ "database",
+ "aks",
+ "performance"
+ ],
+ "formatNotes": "All three. Copilot: path-scoped `.github/instructions/datasource.instructions.md` with applyTo for `**/application*.yml`, `**/application*.properties`, `**/*Repository.java`, and `**/k8s/**`, or `.github/skills/hikari-connection-pool-guardrails/SKILL.md`; one always-on line in `.github/copilot-instructions.md` (\"pool size is a budget: pods at HPA max times maximum-pool-size must fit the database\"). Claude Code: `.claude/skills/hikari-connection-pool-guardrails/SKILL.md`, plus a CLAUDE.md line naming the database connection limit and HPA max. Codex: a \"Database connections\" section in root `AGENTS.md` (or the same SKILL.md under `.agents/skills/`). Pair with spring-data-jpa-query-guardrails for query shape, aks-hpa-requests-limits-guardrails for replica counts, java-virtual-threads-spring-guardrails for concurrency, and spring-boot-micrometer-prometheus-guardrails for metrics. This skill owns how many connections exist and how long anyone may hold one.",
+ "body": "# Skill: HikariCP Connection Pool Guardrails for Spring Boot\n\n## Goal\nEvery service holds a small, fixed number of database connections that fits inside the database's limit even when the deployment is fully scaled out. Requests fail fast with a clear error instead of queueing for 30 seconds, no connection is held across a remote call, dead connections are retired before the network or the database kills them, and pool pressure is visible on a dashboard before users feel it.\n\n## When to apply\n- Adding a datasource to a Spring Boot service, or changing replica counts, HPA limits, or database tier\n- Seeing `SQLTransientConnectionException: ... Connection is not available, request timed out after 30000ms`\n- Seeing `FATAL: sorry, too many clients already` or `remaining connection slots are reserved` on PostgreSQL\n- Latency spikes that line up with `hikaricp_connections_pending` above zero\n- Moving to virtual threads, PgBouncer, or a managed database proxy\n\n## Sizing is a budget, not a guess\nStart from the database, not from the app:\n\n```text\nusable = database max_connections - reserved (admin, replication, migrations, other apps)\nothers = sum over other clients of (pool size * max pods)\nper_pod_max = floor((usable - others) / (HPA maxReplicas + rollout maxSurge))\n```\n\nRules of thumb:\n- A pool larger than the database can do useful work with makes things slower, not faster. HikariCP's own sizing guidance starts near `(cores * 2) + effective disks` **for the database server**, shared by all clients.\n- Most request-response services do well with 5 to 20 connections per pod. Bigger numbers usually hide slow queries or long transactions.\n- Count every pool: each datasource, each replica, batch jobs, migration jobs, and rolling-update surge pods (old and new pods overlap during a deploy).\n\n## Baseline rules\n1. **Fixed-size pool.** Set `maximum-pool-size` from the budget and leave `minimum-idle` unset (it then equals the maximum). A fixed pool avoids connection storms when traffic returns. Name it with `pool-name` so logs and metrics say which pool.\n2. **Fail fast.** `connection-timeout` well under the caller's timeout, typically 1 to 5 seconds, never the 30-second default behind a 10-second ingress timeout. Return 503 with a retry hint on `SQLTransientConnectionException`, not 500.\n3. **Retire connections before something else does.** `max-lifetime` a few minutes shorter than the shortest of: database idle or session limits, proxy or firewall idle timeouts, and credential rotation (for example Entra token lifetime when using passwordless auth). Set `keepalive-time` below any idle timeout on the path (Azure load balancers drop idle TCP flows after a few minutes by default). Keep `idle-timeout` irrelevant by keeping the pool fixed.\n4. **Short transactions.** Set `spring.jpa.open-in-view=false`, so connections are not held for view rendering. No HTTP calls, message publishing that waits for a broker, sleeps, or user think time inside `@Transactional`. Read-only paths use `@Transactional(readOnly = true)`. Batch jobs commit in chunks.\n5. **Time limits on the database side.** A per-role `statement_timeout` and `idle_in_transaction_session_timeout` on PostgreSQL (or the equivalent on your engine), plus a JDBC `socketTimeout` slightly above the statement timeout. A runaway query should end on the server, not only in the client.\n6. **Leak detection where it is cheap.** `leak-detection-threshold` (for example 20 to 60 seconds) in dev and test, and in production only while investigating. A leak warning includes the stack trace of the borrower; fix the code, do not raise the threshold.\n7. **Validation without extra round trips.** Use a JDBC4 driver and do not set `connection-test-query`. Leave `auto-commit` at its default unless the whole codebase manages transactions explicitly, and then set it once and document it.\n8. **Proxies and PgBouncer.** In transaction pooling mode, session state does not survive between transactions: no session-level `SET`, advisory locks, `LISTEN`, or temp tables across transactions. With pgjdbc, disable server-side prepared statements (`prepareThreshold=0`) unless the proxy explicitly supports protocol-level prepared statements. Size the app pool against the proxy's client limit, and the proxy's server pool against the database.\n9. **Virtual threads do not add connections.** With `spring.threads.virtual.enabled=true`, thousands of requests can wait on the same small pool. Treat the pool as the concurrency limit, keep `connection-timeout` short, and add a bulkhead or rate limit in front of database-heavy endpoints rather than growing the pool. Check that the JDBC driver version in use does not pin carrier threads during I/O.\n10. **Separate pools for separate jobs.** Long reports, batch exports, or migrations get their own small pool or their own deployment, so they cannot starve request traffic. Flyway or Liquibase runs as a single job or init step, not in every replica at once.\n11. **Measure it.** Micrometer exposes `hikaricp_connections_active`, `_idle`, `_pending`, `_max`, `hikaricp_connections_acquire_seconds`, `hikaricp_connections_usage_seconds`, and `hikaricp_connections_timeout_total`. Alert on timeouts above zero and on pending above zero for several minutes; graph usage time p95 to find long holders.\n12. **Clean shutdown.** `server.shutdown=graceful` with a `preStop` delay, so in-flight requests finish and the pool closes after them; termination grace period longer than the drain plus the longest statement timeout.\n\n## Copy-ready baseline (application.yml)\n```yaml\nspring:\n jpa:\n open-in-view: false\n datasource:\n url: jdbc:postgresql://${DB_HOST}:5432/${DB_NAME}?socketTimeout=35&ApplicationName=${APP_NAME}\n hikari:\n pool-name: ${APP_NAME}-primary\n maximum-pool-size: ${DB_POOL_MAX:10} # from the connection budget\n connection-timeout: 3000 # ms; well under the request timeout\n max-lifetime: 1500000 # ms; below DB, proxy, and credential limits\n keepalive-time: 120000 # ms; below any idle timeout on the path\n validation-timeout: 1000\n # leak-detection-threshold: 30000 # dev/test, or prod while investigating\n```\n\nDatabase side (PostgreSQL, per application role):\n```sql\nALTER ROLE app_svc SET statement_timeout = '30s';\nALTER ROLE app_svc SET idle_in_transaction_session_timeout = '60s';\nALTER ROLE app_svc CONNECTION LIMIT 120; -- the budget for this service\n```\n\n## Review checklist\n- [ ] Connection budget written down: database limit, reserved slots, HPA max per service, surge pods\n- [ ] `maximum-pool-size` set from the budget; `minimum-idle` unset or equal\n- [ ] `connection-timeout` below the caller's timeout; 503 on pool exhaustion\n- [ ] `max-lifetime` and `keepalive-time` below every idle and session limit on the path\n- [ ] `open-in-view` off; no remote calls inside transactions\n- [ ] Server-side statement and idle-in-transaction timeouts per role\n- [ ] PgBouncer or proxy settings match the pooling mode\n- [ ] Pool metrics on the dashboard, alerts on timeouts and sustained pending\n- [ ] Batch, report, and migration work isolated from request traffic\n- [ ] Graceful shutdown and termination grace period cover the drain\n\n## Anti-patterns\n- Raising `maximum-pool-size` to fix timeouts without finding the slow query or long transaction\n- Pool size copied between services with different replica counts\n- Default 30-second `connection-timeout` behind a shorter gateway timeout\n- `minimum-idle: 0` with a large maximum, causing reconnect storms after quiet periods\n- Leak detection threshold raised until the warnings stop\n- Calling another service, or waiting on a queue, inside `@Transactional`\n\n## Copy-ready SKILL.md stub\n```markdown\n---\nname: hikari-connection-pool-guardrails\ndescription: Use when configuring or reviewing database connection pooling in a Spring Boot service: HikariCP pool size from a connection budget across all replicas at HPA max, fixed pool, connection timeout under the request timeout, maxLifetime and keepalive below idle limits, short transactions with open-in-view off, database-side statement timeouts, leak detection, PgBouncer transaction-mode settings, virtual-thread contention, pool metrics and alerts, and graceful shutdown.\n---\n\nFollow HikariCP Connection Pool Guardrails: size maximum-pool-size from the database connection limit divided across every pod at HPA max, including surge pods and other services, and keep the pool fixed. Set connection-timeout to a few seconds, below the caller's timeout, and map pool exhaustion to 503. Keep max-lifetime and keepalive-time below every database, proxy, load balancer, and credential limit. Turn open-in-view off, keep transactions short, and never call remote services inside one. Put statement and idle-in-transaction timeouts on the database role. Use leak detection in dev and test. Under PgBouncer transaction mode avoid session state and disable server-side prepared statements unless supported. With virtual threads, treat the pool as the concurrency limit. Isolate batch and migration work, publish HikariCP metrics with alerts on timeouts and pending, and shut down gracefully.\n```\n"
}
]
}
From d9210983a4bb8f25672a7fab9b2e11608afb8668 Mon Sep 17 00:00:00 2001
From: Ramkumar Ethiraj <64294490+rmkr-dev@users.noreply.github.com>
Date: Sat, 31 Oct 2026 05:09:28 +0000
Subject: [PATCH 2/2] Add prompt for tuning a Spring Boot connection pool
---
promptbook/prompts.json | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/promptbook/prompts.json b/promptbook/prompts.json
index a4013dd..f28cea8 100644
--- a/promptbook/prompts.json
+++ b/promptbook/prompts.json
@@ -879,6 +879,27 @@
],
"formatNotes": "All three. Point the tool at `.github/workflows/`, CODEOWNERS, and any existing `.github/rulesets/` or Terraform, and paste the output of `gh api repos/{owner}/{repo}/rulesets`, `gh api repos/{owner}/{repo}/branches/main/protection`, and `gh pr checks `. Copilot: rulesets path instructions plus those files in agent mode (or save it as `.github/prompts/migrate-branch-protection-to-rulesets.prompt.md`). Claude Code: the github-rulesets-merge-queue-guardrails skill plus the files. Codex: AGENTS.md branch rules section, then the diff. The prompt outputs commands to review; it never applies rules itself.",
"body": "Task: Move this repository's branch and tag protection into rulesets stored as code, make every required check reliable, and add a merge queue if it is warranted. Finish with ruleset files, workflow fixes, an apply and drift-check process, and a proof plan.\n\nContext placeholders (fill from the repo or ask only if missing):\n- Repository: {{OWNER_REPO}}\n- Plan and owner type: {{PLAN}} (personal, organization on Team, or Enterprise Cloud; decides whether evaluate mode and org rulesets exist)\n- Default branch and release branches: {{BRANCHES}} (e.g. main, release/*)\n- Release tag pattern: {{TAG_PATTERN}} (e.g. v*)\n- Required reviews: {{REVIEWS}} (e.g. 1 approval, code owners, last-push approval)\n- Checks that must pass: {{CHECKS}} (e.g. build, test, dependency-scan, CodeQL; or \"discover from a recent PR\")\n- Merge method: {{MERGE_METHOD}} (merge, squash, or rebase)\n- Merge queue: {{MERGE_QUEUE}} (yes, no, or \"recommend\")\n- Bypass needs: {{BYPASS}} (e.g. release app for tags, platform team on PRs only; or none)\n- Apply method: {{APPLY}} (gh api from a reviewed PR, or Terraform integrations/github)\n\nRequirements:\n\n1. Current state\n - Export with `gh api repos/{{OWNER_REPO}}/rulesets` (and each `rulesets/{id}`) and `gh api repos/{{OWNER_REPO}}/branches//protection`\n - Table: target | source (classic or ruleset) | rule | setting | gap\n - Flag: force push or deletion allowed, no PR rule, admins exempt by default, required checks with no app pinned, tags unprotected, bypass actors with `always`\n\n2. Check inventory\n - From `gh pr checks` on a recent green PR and `.github/workflows/`: check name | workflow file | job id | app | triggers | path or branch filters | matrix\n - Flag required candidates that are path-filtered, renamed recently, duplicated across workflows, or missing `merge_group`\n\n3. Workflow fixes (separate commit, merged first)\n - Unfiltered `pull_request` and `merge_group` triggers on required workflows; move path logic into a `changes` job with a SHA-pinned filter action\n - A final gate job (e.g. `ci-ok`) with `needs:` on all required jobs, `if: always()`, failing when any need failed or was cancelled\n - Stable, unique job `name:` values; no secrets or deploy steps that run only on `merge_group`\n\n4. Ruleset files\n - `.github/rulesets/default-branch.json`: conditions with `~DEFAULT_BRANCH` (plus {{BRANCHES}}), `deletion`, `non_fast_forward`, `pull_request` from {{REVIEWS}} with `dismiss_stale_reviews_on_push`, `require_last_push_approval`, `required_review_thread_resolution`, `allowed_merge_methods` [{{MERGE_METHOD}}]; `required_status_checks` with the gate job and `integration_id: 15368` for Actions checks\n - `.github/rulesets/release-tags.json`: target `tag`, include `refs/tags/{{TAG_PATTERN}}`, `creation`, `update`, `deletion`; bypass only the release actor from {{BYPASS}}\n - Merge queue (if {{MERGE_QUEUE}}): `merge_queue` with `merge_method`, `grouping_strategy: ALLGREEN`, `max_entries_to_build`, `min_entries_to_merge`, `max_entries_to_merge`, `min_entries_to_merge_wait_minutes`, `check_response_timeout_minutes` from CI duration; set `strict_required_status_checks_policy: false`\n - `bypass_actors`: only {{BYPASS}}, `pull_request` mode for people and teams; explain any `exempt`\n - `enforcement: evaluate` first if {{PLAN}} is Enterprise, otherwise a staged rollout note\n - Terraform equivalent if {{APPLY}} is Terraform\n\n5. Apply and drift\n - Apply script or workflow: POST on first create, PUT by id after; run from a reviewed merge with a token that has Administration write; never from a PR branch\n - Scheduled drift workflow on weekdays: fetch live rulesets, normalize (drop `id`, `node_id`, `_links`, `created_at`, `updated_at`, `current_user_can_bypass`, `source`), diff, open or update one issue; no automatic re-apply\n - CODEOWNERS for `.github/rulesets/` and both workflows\n\n6. Migration\n - Order: workflow fixes, rulesets active, `gh ruleset check ` verified, then delete classic protection\n - Note that both systems apply while they overlap\n\n7. Proof\n - PR with failing test: blocked; PR with no approval: blocked; author pushing after approval: approval required again\n - Direct push and force push to the default branch: rejected\n - Non-release actor creating or moving a `{{TAG_PATTERN}}` tag: rejected\n - With a queue: two PRs merge in order; a failing PR is removed; a docs-only PR still gets a green gate\n\nConstraints:\n- Do not apply rulesets or delete classic protection; output files and the commands to review.\n- Don't invent actor ids, team ids, app ids (other than 15368 for GitHub Actions), or check names; use placeholders and list what must be looked up.\n- Minimal workflow diff; do not change build logic.\n- Never give a human `always` bypass, and never let automation enqueue with `GITHUB_TOKEN`.\n- Optimize for GitHub Copilot, Claude Code, and Codex: give concrete files and a checklist.\n\nOutput format:\n1. Current-state table with gaps\n2. Check inventory table with flags\n3. Patch: workflow fixes, ruleset JSON (or Terraform), apply and drift workflows, CODEOWNERS\n4. Migration steps with the exact `gh` commands to review\n5. Proof plan with expected results\n6. Risks and follow-ups (e.g. checks to rename, bypass to remove, org-level rules to propose)\n\nStart with the export. Fix the checks before you require them, and require them before you queue.\n"
+ },
+ {
+ "id": "tune-hikari-connection-pool",
+ "title": "Tune a Spring Boot Service's Database Connection Pool",
+ "whenToUse": "Size and harden a Spring Boot service's HikariCP pool from real numbers: build a connection budget from the database limit and every pool at HPA max, find long transactions and remote calls inside them, set timeouts and lifetimes below the path's idle limits, add database-side statement timeouts, wire pool metrics and alerts, and prove the result with a load test that shows fast failure instead of 30-second waits.",
+ "tools": [
+ "copilot",
+ "claude-code",
+ "codex"
+ ],
+ "tags": [
+ "java",
+ "spring-boot",
+ "hikaricp",
+ "postgresql",
+ "database",
+ "aks",
+ "performance"
+ ],
+ "formatNotes": "All three. Point the tool at `application*.yml`, `@Transactional` classes and repositories, the Deployment and HPA manifests, and paste `SHOW max_connections;`, a `pg_stat_activity` count grouped by `application_name` and `state`, and a screenshot or export of HikariCP metrics if you have them. Copilot: the datasource path instructions plus those files in agent mode (or save it as `.github/prompts/tune-hikari-connection-pool.prompt.md`). Claude Code: the hikari-connection-pool-guardrails skill plus the files. Codex: AGENTS.md database connections section, then the diff. The prompt proposes a config and code diff; it never changes database settings itself.",
+ "body": "Task: Size and harden this Spring Boot service's database connection pool so it fits the database at full scale, fails fast under pressure, and shows its health on a dashboard. Finish with a connection budget, a config and code diff, database-side settings to review, and a load-test plan.\n\nContext placeholders (fill from the repo or ask only if missing):\n- Service and datasources: {{SERVICE}} (e.g. orders-api, one primary datasource)\n- Database engine and tier: {{DATABASE}} (e.g. Azure Database for PostgreSQL Flexible Server, 4 vCores)\n- Database max_connections and reserved slots: {{DB_LIMIT}}\n- Other clients of the same database: {{OTHER_CLIENTS}} (services, jobs, their pool sizes and replica counts)\n- Replicas: {{REPLICAS}} (HPA min and max, rollout maxSurge)\n- Request timeout at the edge: {{EDGE_TIMEOUT}} (e.g. ingress 15s, client 10s)\n- Network path: {{PATH}} (direct, PgBouncer transaction mode, private endpoint, load balancer idle timeout)\n- Credentials: {{CREDENTIALS}} (password, or passwordless token with lifetime)\n- Threads: {{THREADS}} (platform threads with Tomcat max, or virtual threads)\n- Symptoms, if any: {{SYMPTOMS}} (e.g. connection-not-available timeouts, too many clients, p99 spikes)\n\nRequirements:\n\n1. Connection budget\n - Table: client | pool size | replicas at max | surge | total\n - usable = {{DB_LIMIT}} minus reserved; show the per-pod maximum for {{SERVICE}} and whether today's config exceeds it\n - Flag pools copied between services with different replica counts\n\n2. Holding time audit\n - Find `@Transactional` methods and repositories that call HTTP clients, publish and wait on messages, sleep, stream large results, or loop over remote calls\n - Check `spring.jpa.open-in-view` and lazy loading in controllers\n - Table: method | what holds the connection | estimated hold time | fix\n\n3. Pool configuration\n - `maximum-pool-size` from the budget, fixed pool (`minimum-idle` unset), `pool-name`\n - `connection-timeout` below {{EDGE_TIMEOUT}}; map `SQLTransientConnectionException` to 503 with Retry-After\n - `max-lifetime` and `keepalive-time` below every limit in {{PATH}} and {{CREDENTIALS}}, with the reasoning\n - `leak-detection-threshold` in dev and test profiles only\n - If {{PATH}} includes PgBouncer transaction mode: `prepareThreshold=0` (unless supported), no session state across transactions\n - If {{THREADS}} is virtual threads: pool as the concurrency limit, a bulkhead on database-heavy endpoints\n - JDBC `socketTimeout` and `ApplicationName` in the URL\n\n4. Database-side settings (output only)\n - Per-role `statement_timeout`, `idle_in_transaction_session_timeout`, and `CONNECTION LIMIT` matching the budget\n - Note where the managed service sets server parameters instead of SQL\n\n5. Observability\n - Micrometer HikariCP metrics on the actuator endpoint already in use\n - Alerts: `hikaricp_connections_timeout_total` increase above zero; `hikaricp_connections_pending` above zero for 5 minutes; usage p95 above a threshold\n - One dashboard row: active, idle, pending, max, acquire p95, usage p95\n\n6. Shutdown and isolation\n - `server.shutdown=graceful`, `preStop` delay, termination grace period above drain plus statement timeout\n - Batch, report, or migration work on its own pool or deployment; migrations run once, not per replica\n\n7. Proof\n - Load test at expected peak and at 2x: no timeouts at peak; at 2x, requests fail in about the connection timeout with 503, not after 30s\n - Kill a database connection or restart the proxy: pool recovers without restarting pods\n - Rolling deploy at HPA max: total connections stay under the budget\n - Leak test in dev: a deliberate leak produces a leak warning with the stack trace\n\nConstraints:\n- Do not change database server parameters or roles; output the statements to review.\n- Do not raise the pool size to hide slow queries; list the queries instead.\n- Do not invent limits, timeouts, or replica counts; use placeholders and list what must be looked up.\n- Minimal diff; no unrelated refactors.\n- Optimize for GitHub Copilot, Claude Code, and Codex: give concrete files and a checklist.\n\nOutput format:\n1. Connection budget table with the per-pod maximum\n2. Holding time audit table with fixes\n3. Patch: application.yml per profile, exception mapping, code changes for long transactions, manifests\n4. Database-side statements to review\n5. Alerts and dashboard definitions\n6. Proof plan with expected results\n7. Risks and follow-ups (e.g. queries to tune, services to resize, a proxy to consider)\n\nStart with the budget. Shorten how long connections are held before you change how many there are.\n"
}
]
}