Skip to content

Commit ff6c672

Browse files
khareyash05claude
andcommitted
chore(tidb-stmt-cache): scrub customer-identifiable references
The original sample documentation and inline comments named the internal service, recording, message broker tenant, and entity-id format the regression was first reported against. None of those identifiers are needed to explain the bug — the failure mode is a generic property of RoundRobinPartition routing across record/replay sessions. Replace them with neutral phrasing. Behavioural changes: none. Only docs, comments, and the example curl payloads are touched. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 43718c1 commit ff6c672

8 files changed

Lines changed: 57 additions & 57 deletions

File tree

tidb-stmt-cache/README.md

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ against TiDB and Apache Pulsar in a single app:
88
| `GET /api/kv/{v}` and `GET /api/kv/insert-select/{v}` | MySQL Connector/J prepared-statement cache + HikariCP LIFO pool → orphan `COM_STMT_EXECUTE` matcher path |
99
| `POST /events/patch` | Hibernate INSERT + Pulsar `SEND` on a **partitioned** topic with default `RoundRobinPartitionRouter` → the partition-routing replay regression |
1010

11-
Both flows share the same `HikariDataSource` bean (Flipkart's actual shape:
12-
`autoCommit=false`, `prepStmtCacheSize=500`, `prepStmtCacheSqlLimit=2048`,
13-
JPA `provider_disables_autocommit=true`).
11+
Both flows share the same `HikariDataSource` bean shape that drives both
12+
regressions: `autoCommit=false`, `prepStmtCacheSize=500`,
13+
`prepStmtCacheSqlLimit=2048`, JPA `provider_disables_autocommit=true`.
1414

1515
## Why the Pulsar partitioned topic matters
1616

@@ -41,7 +41,7 @@ no recorded mock matches the live topic and replay fails with
4141
│ └── 30-app.yaml carries keploy.io/record-session=true for the webhook
4242
├── pom.xml
4343
└── src/main/java/com/example/tidbstmtcache/
44-
├── DataSourceConfig.java Flipkart-shape HikariCP bean
44+
├── DataSourceConfig.java HikariCP bean (autoCommit=false, …)
4545
├── EventsController.java POST /events/patch — JPA save + Pulsar send
4646
├── EventEntity.java JPA entity for the `events` table
4747
├── EventRepository.java
@@ -68,10 +68,10 @@ APP_PID=$!
6868
curl -s -X POST http://localhost:8080/events/patch \
6969
-H 'Content-Type: application/json' \
7070
-d '{
71-
"entity_id": "FMPP4037630682",
71+
"entity_id": "ENTITY-1001",
7272
"event_name": "delivered",
7373
"event_timestamp": "2026-05-23T17:07:22+05:30",
74-
"task_orchestrator": "FSD"
74+
"task_orchestrator": "ORCH-A"
7575
}'
7676
# Expect: {"message":"Event patched"}
7777

@@ -84,7 +84,7 @@ diff `bin/pulsar-admin topics partitioned-stats persistent://public/default/even
8484
output — partition message counts will land on different partitions
8585
each cold start.
8686

87-
## Full path — k8s-proxy auto-replay (matches Flipkart prod flow)
87+
## Full path — k8s-proxy auto-replay
8888

8989
The k8s-proxy controller watches the namespace for pods carrying
9090
`keploy.io/record-session=true` and injects the keploy-agent sidecar.
@@ -147,7 +147,7 @@ PF_PID=$!
147147
for i in $(seq 1 5); do
148148
curl -s -X POST http://localhost:8080/events/patch \
149149
-H 'Content-Type: application/json' \
150-
-d "{\"entity_id\":\"FMPP$i\",\"event_name\":\"delivered\",\"event_timestamp\":\"2026-05-23T17:07:22+05:30\",\"task_orchestrator\":\"FSD\"}"
150+
-d "{\"entity_id\":\"ENTITY-$i\",\"event_name\":\"delivered\",\"event_timestamp\":\"2026-05-23T17:07:22+05:30\",\"task_orchestrator\":\"ORCH-A\"}"
151151
done
152152

153153
kill $PF_PID
@@ -191,19 +191,23 @@ kubectl -n tidb-pulsar-replay logs deploy/tidb-pulsar-app -c keploy-agent \
191191
`…events`, same payload), the synthetic `SEND_RECEIPT` is returned,
192192
the app returns HTTP 200, the testcase passes.
193193

194-
## Reproducing the Flipkart symptom exactly
195-
196-
The Strowger recording in `Strowger Playgro Global Shipment (1)/testset/`
197-
matches this sample structurally — the `POST /events/patch` body, the
198-
HikariCP shape, and the partitioned Pulsar topic. To run the customer's
199-
mocks against this app:
200-
201-
1. Replace `k8s/30-app.yaml`'s `PULSAR_TOPIC` env with the customer's
202-
topic name (`persistent://toss-relayer/gsm-relayers-prod/toss_EKL-E2E-ORCHESTRATOR_gsm_ns`).
203-
2. Use the customer's `mocks.yaml` instead of a fresh recording.
204-
3. Run step 6 with the customer's test-set ID.
205-
206-
Without the fix you should see the same `payload-aware mock mismatch
207-
for SEND (topic=…partition-7)` log line the customer reported. With the
208-
fix you should see the `SEND` resolve against the customer's
209-
`partition-5` mock and the testcase pass.
194+
## Replaying an existing recording
195+
196+
If you already have a `mocks.yaml` and a `tests/` directory captured
197+
against a structurally similar Pulsar producer (partitioned topic, JPA
198+
`INSERT` before the SEND, HTTP 200 response), this sample can serve as
199+
the replay target:
200+
201+
1. Override `k8s/30-app.yaml`'s `PULSAR_TOPIC` env to match the topic
202+
name in your recorded mocks (`persistent://<tenant>/<namespace>/<topic>`).
203+
2. Load the existing `mocks.yaml` into the test-set storage backend the
204+
k8s-proxy install is configured for, instead of running a fresh
205+
recording.
206+
3. Trigger the replay job with that test-set ID.
207+
208+
Without the matcher fix in `keploy/enterprise`, a replay where the live
209+
producer round-robins to a different partition than the recording will
210+
log `payload-aware mock mismatch for SEND (topic=…partition-<N>)` and
211+
the testcase fails. With the fix, the SEND resolves against the
212+
recorded mock for `…partition-<M>` (same base topic, same payload) and
213+
the testcase passes.

tidb-stmt-cache/docker-compose.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
# reproduce because there is only one partition to route to.
1818
#
1919
# Pin: TiDB v8.5.x is the LTS line current at the time this sample was
20-
# added. Pulsar 4.0.3 matches the broker version typically deployed in
21-
# Flipkart's Strowger environment (Pulsar Server 3.x client compatibility
22-
# is preserved through the 4.x line).
20+
# added. Pulsar 4.0.3 matches the broker version the regression was
21+
# originally observed against (Pulsar Server 3.x client compatibility is
22+
# preserved through the 4.x line).
2323
services:
2424
tidb:
2525
image: pingcap/tidb:v8.5.6

tidb-stmt-cache/pom.xml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
<properties>
2121
<java.version>17</java.version>
2222
<!--
23-
Pulsar 3.1.x is the Java client line the Flipkart recording was
24-
captured against (see CONNECT mocks: clientVersion=Pulsar-Java-v3.1.1
25-
in the Strowger mocks.yaml). Keeping the same major.minor here
26-
means the wire-format the recorder sees in CI matches what
27-
keploy/enterprise has been hardened against.
23+
Pulsar 3.1.x is the Java client line the regression was first
24+
captured against (CONNECT mocks show clientVersion=Pulsar-Java-v3.1.1).
25+
Keeping the same major.minor here means the wire-format the
26+
recorder sees in CI matches what keploy/enterprise has been
27+
hardened against.
2828
-->
2929
<pulsar.client.version>3.1.1</pulsar.client.version>
3030
</properties>
@@ -39,8 +39,8 @@
3939
<artifactId>spring-boot-starter-jdbc</artifactId>
4040
</dependency>
4141
<!--
42-
JPA + Hibernate are added for the Pulsar/TiDB Flipkart scenario:
43-
the production datasource bean we are replicating (autoCommit=false,
42+
JPA + Hibernate are added for the Pulsar/TiDB scenario: the
43+
datasource bean we are replicating (autoCommit=false,
4444
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true)
4545
only behaves correctly when the JPA EntityManager owns the
4646
transactional boundary. JdbcTemplate alone won't reproduce the
@@ -68,9 +68,9 @@
6868
MessageRoutingMode.RoundRobinPartition (Pulsar's default) against
6969
a topic pre-created with 8 partitions. The starting-partition
7070
cursor is randomised per producer instance, so the partition a
71-
given SEND lands on at record time will differ from replay time
72-
which is exactly the regression keploy/enterprise's baseTopic()
73-
change handles.
71+
given SEND lands on at record time will differ from replay time
72+
which is exactly the regression keploy/enterprise's baseTopic()
73+
matcher loosening handles.
7474
-->
7575
<dependency>
7676
<groupId>org.apache.pulsar</groupId>

tidb-stmt-cache/src/main/java/com/example/tidbstmtcache/DataSourceConfig.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@
99
import org.springframework.jdbc.core.JdbcTemplate;
1010

1111
/**
12-
* HikariCP pool against TiDB :4000 with the same bean shape the Flipkart
13-
* Global-Shipment-Master service uses in production. Two distinct keploy
14-
* regressions are exercised by this single sample:
12+
* HikariCP pool against TiDB :4000. Two distinct keploy regressions are
13+
* exercised by this single sample:
1514
*
1615
* - Orphan COM_STMT_EXECUTE (TiDB prepared-statement cache): driven by
1716
* useServerPrepStmts + cachePrepStmts + prepStmtCacheSize on the

tidb-stmt-cache/src/main/java/com/example/tidbstmtcache/EventEntity.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@
1010
import java.time.Instant;
1111

1212
/**
13-
* Mirrors the Flipkart Global-Shipment-Master event row that the
14-
* /events/patch endpoint persists before fanning the event out to a
15-
* partitioned Pulsar topic. The exact column types are deliberately
16-
* boring — we are not validating Hibernate type mapping here, only
17-
* that an INSERT + COMMIT goes through MySQL Connector/J in a way the
18-
* keploy MySQL parser already covers.
13+
* Event row that the /events/patch endpoint persists before fanning the
14+
* event out to a partitioned Pulsar topic. The exact column types are
15+
* deliberately boring — we are not validating Hibernate type mapping
16+
* here, only that an INSERT + COMMIT goes through MySQL Connector/J in
17+
* a way the keploy MySQL parser already covers.
1918
*/
2019
@Entity
2120
@Table(name = "events")

tidb-stmt-cache/src/main/java/com/example/tidbstmtcache/EventsController.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414
import java.util.Map;
1515

1616
/**
17-
* Mirrors the Flipkart Global-Shipment-Master /events/patch endpoint:
18-
* persists an event row through Hibernate (TiDB) and fans it out to a
19-
* partitioned Pulsar topic. The request/response shapes match the
20-
* Strowger recording (test post-events-patch-1.yaml) so a recording
21-
* captured against this sample produces mocks structurally identical
22-
* to the customer's.
17+
* POST /events/patch — persists an event row through Hibernate (TiDB)
18+
* and fans it out to a partitioned Pulsar topic. The request/response
19+
* shapes are intentionally generic so any recording captured against
20+
* this sample can be replayed with the keploy enterprise agent.
2321
*
2422
* Why a synchronous .send() rather than sendAsync(): we want the
2523
* record-time mock for SEND_RECEIPT and the in-transaction COMMIT to

tidb-stmt-cache/src/main/java/com/example/tidbstmtcache/PulsarConfig.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
*
2525
* Why we do NOT pin a single partition (e.g. SinglePartition + fixed
2626
* messageKey): pinning would mask the bug, which is the whole reason
27-
* this sample exists. The point is to reproduce the Flipkart routing
28-
* mismatch end-to-end so the matcher loosening in
29-
* keploy/enterprise (baseTopic in pulsar/replayer/replayer.go) can be
30-
* verified against a real Java producer.
27+
* this sample exists. The point is to reproduce the routing mismatch
28+
* end-to-end so the matcher loosening in keploy/enterprise (baseTopic
29+
* in pulsar/replayer/replayer.go) can be verified against a real Java
30+
* producer.
3131
*
3232
* Why we accept a topic that may not yet exist on broker startup:
3333
* docker-compose's pulsar-init container runs `pulsar-admin topics

tidb-stmt-cache/src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
server.port=8080
22

3-
# --- TiDB DataSource (Flipkart-shape) ---
3+
# --- TiDB DataSource ---
44
# TiDB :4000 speaks the MySQL wire protocol, so the MySQL Connector/J 8.x
55
# driver works as-is. JDBC URL parameters that matter:
66
#

0 commit comments

Comments
 (0)