refactor: batch paykit contact cleanup#1099
Conversation
Greptile SummaryThis PR batches private Paykit contact publication and cleanup work. The main changes are:
Confidence Score: 4/5The batched cleanup path can skip remote cleanup or block unrelated contacts, so these cases should be fixed before merging.
app/src/main/java/to/bitkit/repositories/PrivatePaykitRepo.kt
|
| Filename | Overview |
|---|---|
| app/src/main/java/to/bitkit/repositories/PrivatePaykitRepo.kt | Adds shared linked-peer snapshots, batched cleanup and draining, and per-contact cache reconciliation. |
| app/src/test/java/to/bitkit/repositories/PrivatePaykitRepoTest.kt | Adds valid tests for one linked-peer read, one shared drain, and partial cleanup failure. |
Reviews (1): Last reviewed commit: "refactor: batch paykit contact cleanup" | Re-trigger Greptile
| val publicKeys = publicKeys.mapNotNull(::normalizedPublicKey).distinct() | ||
| if (publicKeys.isEmpty()) return@runSuspendCatching Unit |
There was a problem hiding this comment.
Invalid Key Reports Cleanup Success
When a pending deleted-contact key cannot be normalized, mapNotNull drops it and the empty batch returns success. retryPendingDeletedContactEndpointRemoval then removes the cached contact and retry marker even though its remote payment lists were never cleared, so that cleanup is not attempted again.
There was a problem hiding this comment.
Fixed in e56f9dc. Invalid keys now return InvalidPublicKey instead of being dropped from an empty batch, so the retry marker and cached state are preserved for another cleanup attempt. Added a regression test for this case.
| val publicKeys = publicKeys.mapNotNull(::normalizedPublicKey).distinct() | ||
| if (publicKeys.isEmpty()) return@runSuspendCatching Unit | ||
|
|
||
| val linkedReceiverPaths = linkedReceiverPathsByPublicKey() |
There was a problem hiding this comment.
Shared Snapshot Breaks Failure Isolation
When this linkedPeers() call throws, the batch exits before clearing any contact. The previous no-argument flow caught each contact's failure and continued with later contacts, so one transient SDK failure now blocks cleanup progress for every contact in the pass.
There was a problem hiding this comment.
Fixed in e56f9dc. The shared snapshot remains the fast path, but if it fails we retry peer inspection per contact. One contact's failure no longer blocks later contacts, and its locally cached published paths are still cleared while its state remains pending. Added regression coverage for the partial-failure case.
| val linkedReceiverPaths = linkedReceiverPathsByPublicKey() | ||
| val preparation = clearPrivatePaymentLists(publicKeys, linkedReceiverPaths) |
There was a problem hiding this comment.
Snapshot Misses Newly Linked Paths
If a receiver path becomes linked after this batch-wide snapshot but before its contact is processed, that path is omitted from receiverPathsForCleanup. The contact can still be marked successful and lose its cache and retry marker while the remote payment list on the missed path remains published.
There was a problem hiding this comment.
I don't think this can leave an untracked payment list. Cleanup unions the snapshot with publishedPrivatePaymentReceiverPaths; queued publications are recorded in that local cache before delivery, and publication/cleanup run on the serialized dispatcher. A path becoming linked by itself does not publish a payment list, so any newly linked path with a list to clear is already covered by the cached published path.
There was a problem hiding this comment.
You're right. The two invariants together close the gap I was concerned about:
receiverPathsForCleanupunions the linked-peer snapshot withpublishedPrivatePaymentReceiverPaths— the local cache independently covers every path that was ever published.- The local cache is written before delivery, and publication and cleanup are both serialized on
serializedDispatcher, preventing any interleaving that could leave an untracked path.
A newly linked path without a prior publication has nothing in the remote list to clear, so missing it from the snapshot is harmless. My original comment was incorrect — sorry for the noise.
6959e91 to
9bae4d5
Compare
e56f9dc to
9cf060e
Compare
b27d8b5 to
eda7df2
Compare
Description
This PR builds on #1098 to address the Paykit cleanup performance follow-ups from iOS #620:
No user-facing behavior changes are intended.
Preview
N/A — repository-only refactor.
QA Notes
Manual Tests
N/A
Automated Checks
PrivatePaykitRepoTest.kt: all 37 focused tests passed, including the three new batching and failure-isolation tests../gradlew compileDevDebugKotlinpassed../gradlew testDevDebugUnitTestpassed../gradlew detektpassed with only pre-existing findings outside this change.git diff --checkpassed.