Skip to content

feat: add ps-cache-kotlin sample for connection-affinity testing#123

Merged
slayerjain merged 4 commits intomainfrom
feat/ps-cache-kotlin-sample
Apr 16, 2026
Merged

feat: add ps-cache-kotlin sample for connection-affinity testing#123
slayerjain merged 4 commits intomainfrom
feat/ps-cache-kotlin-sample

Conversation

@slayerjain
Copy link
Copy Markdown
Member

@slayerjain slayerjain commented Apr 16, 2026

Bug: JDBC PS-cache + connection eviction causes wrong mock data during replay

When HikariCP evicts a connection, the JDBC driver's prepared statement cache resets. The recorded mocks from the evicted connection have warm-cache structure (Bind-only) while replay sends cold-cache structure (Parse+Bind+Describe+Execute). Combined with bindParamMatchLen mode treating all int4 params as equal (4 bytes), the matcher picks mocks from the wrong connection window -- returning Alice's financial data for Charlie's account.

This was reported by a customer running a Kotlin/Spring Boot app. This sample reproduces the exact failure.

How to reproduce the failure

# Prerequisites
docker run -d --name pg-demo -e POSTGRES_PASSWORD=testpass -e POSTGRES_DB=demodb -p 5433:5432 postgres:16
docker exec pg-demo psql -U postgres -d demodb -c "
  CREATE SCHEMA IF NOT EXISTS travelcard;
  CREATE TABLE IF NOT EXISTS travelcard.travel_account (
    id SERIAL PRIMARY KEY, member_id INT NOT NULL UNIQUE,
    name TEXT NOT NULL, balance INT NOT NULL DEFAULT 0);
  INSERT INTO travelcard.travel_account (member_id, name, balance) VALUES
    (19, 'Alice', 1000), (23, 'Bob', 2500),
    (31, 'Charlie', 500), (42, 'Diana', 7500)
  ON CONFLICT (member_id) DO NOTHING;"

cd ps-cache-kotlin
mvn package -DskipTests -q

# Record with keploy v3.3.75 (or any version before the fix)
sudo keploy record -c "java -jar target/kotlin-app-1.0.0.jar"

# In another terminal, run these curls in order:
curl "http://localhost:8090/account?member=19"   # Alice  (warms PS cache on Connection A)
curl "http://localhost:8090/account?member=23"   # Bob    (cached PS, Bind-only)
curl "http://localhost:8090/evict"                # Force HikariCP to evict all connections
curl "http://localhost:8090/account?member=31"   # Charlie (new Connection B, cold PS cache)
curl "http://localhost:8090/account?member=42"   # Diana   (cached PS on Connection B)

# Stop recording (Ctrl+C), then replay:
sudo keploy test -c "java -jar target/kotlin-app-1.0.0.jar" --skip-coverage

Expected failure: The post-eviction /account?member=31 test fails:

EXPECTED: {"id":3, "memberId":31, "name":"Charlie", "balance":500}
ACTUAL:   {"id":1, "memberId":19, "name":"Alice",   "balance":1000}  <- WRONG PERSON

Note: The exact test number that fails varies depending on how many health-check requests keploy captures during recording (e.g. test-5, test-6, or test-7).

With obfuscation enabled (worse): 2 failures instead of 1

See README.md for full details.

Fix

Recording-connection affinity in the Postgres mock matcher: keploy/integrations#121

Kotlin + Spring Boot + JDBC sample that demonstrates the PS-cache mock
mismatch.  Uses HikariCP max-pool-size=1, prepareThreshold=1, and a
/evict endpoint to force connection cycling.

The test records 4 /account requests across 2 connection windows.
Without the affinity fix (keploy/integrations#121), test-5 returns
Alice's data for Charlie's request.

Signed-off-by: slayerjain <shubhamkjain@outlook.com>
Copilot AI review requested due to automatic review settings April 16, 2026 17:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new ps-cache-kotlin sample app (Kotlin + Spring Boot + JDBC/Postgres) intended to reproduce and validate PS-cache connection-affinity behavior across two connection “windows” (with an explicit pool eviction in between), supporting verification of keploy/integrations#121.

Changes:

  • Introduces a Spring Boot Kotlin/JDBC API with /account (member lookup) and /evict (Hikari soft-eviction) endpoints.
  • Adds Docker-based local environment (Postgres + API) plus seed SQL for deterministic data.
  • Adds a shell script to exercise two request windows separated by eviction to detect mock mismatch regressions.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
ps-cache-kotlin/src/main/kotlin/com/demo/App.kt Implements the API endpoints and connection-eviction behavior used to trigger PS-cache affinity scenarios.
ps-cache-kotlin/src/main/resources/application.properties Configures Postgres JDBC URL + prepareThreshold, and Hikari pool sizing to enforce connection reuse.
ps-cache-kotlin/docker-compose.yml Provides a runnable Postgres + API stack with healthchecks and env wiring.
ps-cache-kotlin/Dockerfile Builds and runs the Spring Boot fat jar in a container.
ps-cache-kotlin/pom.xml Maven build for Kotlin + Spring Boot web/jdbc + Postgres driver.
ps-cache-kotlin/init.sql Seeds the schema/table and deterministic member records for the test scenario.
ps-cache-kotlin/test.sh Drives the two-window request sequence (including /evict) to reproduce/verify the mismatch behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +10 to +34
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3

echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3

echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1

echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3

echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This uses curl -s, which will not fail the script on HTTP 4xx/5xx responses. For a regression test, use curl’s fail-on-error behavior (e.g., -f plus -S) so server errors cause a non-zero exit.

Suggested change
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
curl -fsS "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -fsS "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -fsS "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -fsS "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -fsS "$BASE_URL/account?member=42"

Copilot uses AI. Check for mistakes.
Comment on lines +85 to +89
hikari.hikariPoolMXBean?.softEvictConnections()
// Also wait briefly for eviction
Thread.sleep(200)
return mapOf("evicted" to true, "active" to (hikari.hikariPoolMXBean?.activeConnections ?: 0),
"idle" to (hikari.hikariPoolMXBean?.idleConnections ?: 0))
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The endpoint reports evicted=true even if hikari.hikariPoolMXBean is null, which can yield a false-positive success response. Consider returning an error/evicted=false when the MXBean isn’t available, or ensure it’s non-null before responding.

Suggested change
hikari.hikariPoolMXBean?.softEvictConnections()
// Also wait briefly for eviction
Thread.sleep(200)
return mapOf("evicted" to true, "active" to (hikari.hikariPoolMXBean?.activeConnections ?: 0),
"idle" to (hikari.hikariPoolMXBean?.idleConnections ?: 0))
val poolMxBean = hikari.hikariPoolMXBean
?: return mapOf(
"evicted" to false,
"error" to "Hikari pool MXBean is unavailable; verify Hikari management is enabled and retry the request."
)
poolMxBean.softEvictConnections()
// Also wait briefly for eviction
Thread.sleep(200)
return mapOf(
"evicted" to true,
"active" to poolMxBean.activeConnections,
"idle" to poolMxBean.idleConnections
)

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +64
} else {
mapOf("error" to "not found", "member_id" to memberId)
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

/account returns an error map with HTTP 200 when the member isn’t found. If this is meant to behave like a real API (and to make failures obvious in tests), return a 404 status (e.g., via ResponseEntity.notFound()), or otherwise clearly signal the failure in the HTTP response code.

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +10 to +34
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3

echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3

echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1

echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3

echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This uses curl -s, which will not fail the script on HTTP 4xx/5xx responses. For a regression test, use curl’s fail-on-error behavior (e.g., -f plus -S) so server errors cause a non-zero exit.

Suggested change
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
curl -fsS "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -fsS "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -fsS "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -fsS "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -fsS "$BASE_URL/account?member=42"

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +10 to +34
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3

echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3

echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1

echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3

echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This uses curl -s, which will not fail the script on HTTP 4xx/5xx responses. For a regression test, use curl’s fail-on-error behavior (e.g., -f plus -S) so server errors cause a non-zero exit.

Suggested change
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
curl -fsS "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -fsS "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -fsS "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -fsS "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -fsS "$BASE_URL/account?member=42"

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +86
@GetMapping("/evict")
fun evict(): Map<String, Any> {
val hikari = dataSource as HikariDataSource
hikari.hikariPoolMXBean?.softEvictConnections()
// Also wait briefly for eviction
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

/evict is an unauthenticated endpoint that churns the connection pool. If this sample is ever exposed beyond local/dev, it’s an easy DoS vector; consider guarding it behind a profile/property, requiring a shared-secret header, or clearly documenting it as dev-only.

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +67
val ps = conn.prepareStatement(
"""SELECT id, member_id, name, balance
FROM travelcard.travel_account
WHERE member_id = ?"""
)
ps.setInt(1, memberId)
val rs = ps.executeQuery()

val result = if (rs.next()) {
Account(
id = rs.getInt("id"),
memberId = rs.getInt("member_id"),
name = rs.getString("name"),
balance = rs.getInt("balance")
)
} else {
mapOf("error" to "not found", "member_id" to memberId)
}

rs.close()
ps.close()
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

If anything throws after prepareStatement/executeQuery, the ResultSet/PreparedStatement won’t be closed (they’re only closed on the happy path). Use Kotlin use {} (or a finally) around ps and rs so they are always closed before the connection is returned to the pool.

Suggested change
val ps = conn.prepareStatement(
"""SELECT id, member_id, name, balance
FROM travelcard.travel_account
WHERE member_id = ?"""
)
ps.setInt(1, memberId)
val rs = ps.executeQuery()
val result = if (rs.next()) {
Account(
id = rs.getInt("id"),
memberId = rs.getInt("member_id"),
name = rs.getString("name"),
balance = rs.getInt("balance")
)
} else {
mapOf("error" to "not found", "member_id" to memberId)
}
rs.close()
ps.close()
val result = conn.prepareStatement(
"""SELECT id, member_id, name, balance
FROM travelcard.travel_account
WHERE member_id = ?"""
).use { ps ->
ps.setInt(1, memberId)
ps.executeQuery().use { rs ->
if (rs.next()) {
Account(
id = rs.getInt("id"),
memberId = rs.getInt("member_id"),
name = rs.getString("name"),
balance = rs.getInt("balance")
)
} else {
mapOf("error" to "not found", "member_id" to memberId)
}
}
}

Copilot uses AI. Check for mistakes.
conn.rollback()
throw e
}
}!!
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The non-null assertion on the result of jdbc.execute { ... } can throw an NPE at runtime (JdbcTemplate’s execute returns a nullable type). Prefer returning a non-null value without !! (e.g., use the generic execute<T>/ConnectionCallback<T> form or handle the null case explicitly).

Suggested change
}!!
} ?: throw IllegalStateException(
"Database query returned no result; retry the request or verify the database connection state."
)

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +10 to +34
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3

echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3

echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1

echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3

echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This uses curl -s, which will not fail the script on HTTP 4xx/5xx responses. For a regression test, use curl’s fail-on-error behavior (e.g., -f plus -S) so server errors cause a non-zero exit.

Suggested change
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
curl -fsS "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -fsS "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -fsS "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -fsS "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -fsS "$BASE_URL/account?member=42"

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +10 to +34
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3

echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3

echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1

echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3

echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This uses curl -s, which will not fail the script on HTTP 4xx/5xx responses. For a regression test, use curl’s fail-on-error behavior (e.g., -f plus -S) so server errors cause a non-zero exit.

Suggested change
curl -s "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -s "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -s "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -s "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -s "$BASE_URL/account?member=42"
curl -fsS "$BASE_URL/account?member=19"
echo ""
sleep 0.3
echo " /account?member=23:"
curl -fsS "$BASE_URL/account?member=23"
echo ""
sleep 0.3
echo ""
echo "--- Evict (force new connection) ---"
echo " /evict:"
curl -fsS "$BASE_URL/evict"
echo ""
sleep 1
echo ""
echo "--- Window 2: Connection B ---"
echo " /account?member=31:"
curl -fsS "$BASE_URL/account?member=31"
echo ""
sleep 0.3
echo " /account?member=42:"
curl -fsS "$BASE_URL/account?member=42"

Copilot uses AI. Check for mistakes.
… curl -fSs

- Use Kotlin use{} blocks for PreparedStatement and ResultSet cleanup
- Return 404 ResponseEntity when member not found
- Handle null HikariPoolMXBean with proper error response
- Remove non-null assertion (!!) — return ResponseEntity directly
- Use curl -fSs in test.sh to fail on HTTP errors

Signed-off-by: slayerjain <shubhamkjain@outlook.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +17 to +18
sleep 0.3

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

sleep 0.3 relies on non-POSIX fractional sleep support and can fail on some environments/shells. Consider using integer sleeps or an alternative portable delay mechanism so this script runs consistently across platforms.

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +31 to +32
sleep 0.3

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

sleep 0.3 relies on non-POSIX fractional sleep support and can fail on some environments/shells. Consider using integer sleeps or an alternative portable delay mechanism so this script runs consistently across platforms.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,7 @@
server.port=8080
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:testdb}?prepareThreshold=1&preparedStatementCacheQueries=256
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The DB port defaults to 5432 in application.properties, but docker-compose.yml exposes Postgres on host port 5433. If the intended workflow includes running the app locally against the compose DB, consider aligning the default (DB_PORT) or the compose port mapping to avoid connection failures without extra env vars.

Suggested change
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:testdb}?prepareThreshold=1&preparedStatementCacheQueries=256
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5433}/${DB_NAME:testdb}?prepareThreshold=1&preparedStatementCacheQueries=256

Copilot uses AI. Check for mistakes.
?: return ResponseEntity.status(500).body(mapOf("error" to "pool MXBean not available"))

mxBean.softEvictConnections()
Thread.sleep(200)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

/evict blocks the request thread with a fixed Thread.sleep(200), which adds latency and makes eviction timing dependent on a hard-coded delay. Prefer returning immediately (the caller already waits), or poll for the pool state with a bounded timeout if you need to ensure a new connection is established before responding.

Suggested change
Thread.sleep(200)

Copilot uses AI. Check for mistakes.
Comment thread ps-cache-kotlin/test.sh Outdated
Comment on lines +12 to +13
sleep 0.3

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

sleep 0.3 relies on non-POSIX fractional sleep support and can fail on some environments/shells. Consider using integer sleeps or an alternative portable delay mechanism so this script runs consistently across platforms.

Copilot uses AI. Check for mistakes.
Signed-off-by: slayerjain <shubhamkjain@outlook.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
ports:
- "5433:5432"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

db is published on host port 5433, but the app’s default DB_PORT in application.properties is 5432. If someone runs Postgres via this compose file and runs the app locally (not in the api container), the default connection settings will point to the wrong port. Consider either mapping 5432:5432 here, or changing the default DB_PORT to 5433 (and documenting the intended run mode).

Suggested change
- "5433:5432"
- "5432:5432"

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +56

conn.commit()
account
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

conn.commit() is called while the ResultSet / PreparedStatement are still inside their use {} scopes. Some JDBC drivers can close cursors/result sets on commit, which can lead to surprising behavior. Consider moving the commit so it happens after the use blocks have completed (resources closed), and keeping rollback/cleanup centralized.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +73
@GetMapping("/evict")
fun evict(): ResponseEntity<Map<String, Any>> {
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

/evict changes server state (evicts pooled connections) but is exposed as a GET. For correctness with HTTP semantics (and to avoid accidental triggering by caches/prefetchers), consider making this a POST endpoint and updating test.sh accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +81
?: return ResponseEntity.status(500).body(mapOf("error" to "not a HikariDataSource"))

val mxBean = hikari.hikariPoolMXBean
?: return ResponseEntity.status(500).body(mapOf("error" to "pool MXBean not available"))

mxBean.softEvictConnections()
Thread.sleep(500)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

Avoid Thread.sleep on the request thread; it blocks the server thread pool and makes response latency non-deterministic. If you need to wait for eviction to take effect for the test, consider polling the pool state with a bounded timeout (or just return immediately and let the next /account request establish the new connection).

Suggested change
?: return ResponseEntity.status(500).body(mapOf("error" to "not a HikariDataSource"))
val mxBean = hikari.hikariPoolMXBean
?: return ResponseEntity.status(500).body(mapOf("error" to "pool MXBean not available"))
mxBean.softEvictConnections()
Thread.sleep(500)
?: return ResponseEntity.status(500).body(
mapOf(
"error" to "not a HikariDataSource",
"next_step" to "Verify that the application is configured to use HikariCP before calling /evict."
)
)
val mxBean = hikari.hikariPoolMXBean
?: return ResponseEntity.status(500).body(
mapOf(
"error" to "pool MXBean not available",
"next_step" to "Enable HikariCP pool management or confirm the datasource exposes a pool MXBean, then retry /evict."
)
)
mxBean.softEvictConnections()

Copilot uses AI. Check for mistakes.
Signed-off-by: slayerjain <shubhamkjain@outlook.com>
@slayerjain slayerjain merged commit 5c6aeac into main Apr 16, 2026
2 checks passed
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.

2 participants