fix(#5050): gRPC lifecycle & cleanup#5197
Conversation
…empotent stopService, remove client System.out, proto docs, explicit-lock stub) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Tick the box to add this pull request to the merge queue (same as
|
There was a problem hiding this comment.
Code Review
This pull request addresses issue #5050 by resolving resource leaks and ensuring idempotency in the gRPC plugin lifecycle. It removes a leftover System.out.print statement in ProtoUtils.toProtoRecord and adds a corresponding regression test. In GrpcServerPlugin, it ensures that only a single instance of ArcadeDbGrpcService and HealthStatusManager are created and reused when configuring multiple server builders, preventing duplicate reaper threads and registry leaks. It also introduces an AtomicBoolean guard to make stopService() idempotent, along with regression tests for these lifecycle improvements. The review feedback suggests making the package-private configureServer method synchronized to prevent potential race conditions during the check-then-act initialization of shared volatile fields.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| } | ||
|
|
||
| private void configureServer(ServerBuilder<?> serverBuilder, ContextConfiguration config) { | ||
| void configureServer(ServerBuilder<?> serverBuilder, ContextConfiguration config) { |
There was a problem hiding this comment.
Since configureServer is now package-private and can be invoked from external contexts (such as tests), and it performs check-then-act initialization on the shared volatile fields grpcService and healthManager, there is a potential race condition if it is called concurrently.
Making the configureServer method synchronized is a simple and robust way to guarantee thread-safe initialization of these shared resources with negligible overhead.
| void configureServer(ServerBuilder<?> serverBuilder, ContextConfiguration config) { | |
| synchronized void configureServer(ServerBuilder<?> serverBuilder, ContextConfiguration config) { |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
🟢 Coverage 100.00% diff coverage · -6.75% coverage variation
Metric Results Coverage variation ✅ -6.75% coverage variation Diff coverage ✅ 100.00% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (6fac1d8) 137532 102631 74.62% Head commit (bdf7d80) 169379 (+31847) 114955 (+12324) 67.87% (-6.75%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#5197) 15 15 100.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
PR Review: fix(#5050) gRPC lifecycle & cleanupReviewed the full diff plus surrounding context in Strengths
Minor suggestions (non-blocking)
Test coverageGood. Nothing here is blocking - the core fixes are correct and safe. LGTM. 👍 |
…cycle, hoist stdout assert out of tx Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review: PR #5197 - gRPC lifecycle & cleanupReviewed against Verified correct
Suggestions
Nits
Nice work - the fixes are correct and the tests target the right seams ( |
…tree Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
PR Review: fix(#5050) gRPC lifecycle & cleanup Reviewed against the changed files and the surrounding gRPC code. This is a clean, well-scoped set of fixes and every claim in the description was verifiable against the source. Nice work, especially the regression tests and the design doc. Correctness - verified
Minor nits (non-blocking)
Reusing one service across two ServerBuilders Worth a sentence in a comment: the same Test coverage - good
Overall: LGTM. Only the fully-qualified-name nit is a real (trivial) style deviation; everything else is optional polish. |
…ment cross-builder service reuse Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR Review: gRPC lifecycle & cleanup (#5197)Reviewed the full diff against the source. This is a clean, well-targeted set of fixes and I verified each one against the code paths it claims to touch. Nice work - the fixes are correct and each is backed by a regression test. Verified correct
Minor / non-blocking
Style/conventionsConsistent with the codebase - Overall: LGTM. The only actionable item I'd flag for merge is the tracking/scratch doc (point 3). |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5197 +/- ##
============================================
+ Coverage 65.64% 66.06% +0.42%
+ Complexity 918 914 -4
============================================
Files 1696 1696
Lines 137532 137534 +2
Branches 29434 29437 +3
============================================
+ Hits 90287 90867 +580
+ Misses 34941 34350 -591
- Partials 12304 12317 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closes #5050
Summary
Resolves the lower-severity gRPC lifecycle/housekeeping findings from the 2026-07 audit:
grpc.mode=both,GrpcServerPlugin.configureServerwas invoked once per server builder, each constructing a freshArcadeDbGrpcServiceand overwritingthis.grpcService/healthManager;stopServiceclosed only the last instance, leaking the first service's idle-reaper daemon thread and its transaction registry. The service and health manager are now built once and reused across both builders.stopServiceis now idempotent/concurrent-safe via anAtomicBoolean stoppedguard (the JVM shutdown hook and the plugin-lifecycle stop can both call it); the lifecycle fields read bygetStatus()are nowvolatile.System.out.print(...)inProtoUtils.toProtoRecordthat fired for every property of every record on the client write path (stdout flood + property-value leak).InsertOptions.TransactionModeproto comments (PER_STREAMcommits once at stream end;PER_ROWcommits per row;PER_BATCHcommits everyserver_batch_sizerows), verified against the commit sites inArcadeDbGrpcService.acquireLock()resolvedRemoteGrpcTransactionExplicitLockto a private nested stub (nobucket/type/lockoverrides), shadowing the fully-implemented top-level class. The issue proposed deleting the top-level file, but it carries the real LOCK-command logic and is exercised by the existingRemoteGrpcTransactionExplicitLockIT; the correct resolution is "make the code use it", so the redundant nested stub was removed andacquireLock()now resolves to the real implementation.Test plan
Issue5050GrpcPluginLifecycleTest(grpcw): "both"-mode configuration reuses a singleArcadeDbGrpcService(no reaper-thread leak);stopServiceis idempotent under repeated invocation.Issue5050ProtoUtilsNoStdoutTest(grpc-client):toProtoRecordwrites nothing to stdout.GrpcServerPluginTest,ArcadeDbGrpcServiceReaperTest, andRemoteGrpcTransactionExplicitLockITstill compile/pass (the latter validates the restored top-level explicit-lock class).grpc,grpcw,grpc-clientmodules compile.