refactor(framework): decouple Manager from TronJsonRpcImpl

0X
1mo ago
+612-88

What does this PR do?

Removes the Manager → TronJsonRpcImpl reverse dependency left by #6732, where core-layer Manager holds the json-rpc filter consumer through a @Lazy injection.

  • Adds a standalone FilterCapsuleQueue bean; Manager.postBlockFilter/postLogsFilter produce into it, so Manager no longer references anything under org.tron.core.services.jsonrpc (repo-wide framework/src/main is now @Lazy-free).
  • Moves the consumer loop into TronJsonRpcImpl: started by @PostConstruct when isJsonRpcFilterEnabled(), single daemon thread, stopped by close().
  • TronJsonRpcImpl constructor becomes (NodeInfoService, Wallet, Manager); setManager() is removed and the direct-construction test sites are migrated.
  • close() is rewritten: an AtomicBoolean guard makes it idempotent and serves as a visibility-safe stop flag, the loop exits on interrupt, and the consumer is awaited before logsFilterPool shuts down so an in-flight capsule completes on graceful shutdown.
  • ApplicationImpl.shutdown() now closes the consumer after producers stop and before dbManager.close(); the later Spring-destruction close() is a no-op.
  • The instanceof dispatch logs a warning for unknown FilterTriggerCapsule subtypes instead of silently dropping them.

Runtime behavior of the filter API is unchanged: same unbounded queue, same discard-on-shutdown semantics, one consumer shared by the FullNode/solidity/PBFT json-rpc services.

Why are these changes required?

Follow-up agreed in the #6732 review (see discussion). FullNode sets allowCircularReferences(false); @Lazy, like ObjectProvider or a runtime getBean(), only makes Spring tolerate the cycle. The reverse core → API edge stays, obscuring the component graph, and later json-rpc cleanups keep copying the pattern. This PR removes the edge instead.

This PR has been tested by:

  • Unit Tests
  • Manual Testing
    • private chain: block production with registered filters; eth_getFilterChanges delivers; SIGTERM log order confirms consumer → logs-filter-pool → dbManager → context close, single shutdown episode, no errors
    • Nile and mainnet lite nodes: 5 restart cycles each with 100 filters created and polled per cycle (~2,500 queries/cycle, zero rpc errors); on mainnet the log path delivered 20k+ real contract log entries through the new queue; filters correctly report filter not found after restart; no RejectedExecutionException, no bean-cycle errors, shutdown order identical in every cycle

Follow up

Extra details


Summary by cubic

Decouples the core Manager from JSON-RPC TronJsonRpcImpl by inserting a FilterCapsuleQueue between producers and the consumer. This removes the Spring circular reference, hardens shutdown (idempotent close, clean exit on interrupt, consumer stops before logsFilterPool), and keeps filter API behavior unchanged.

  • Introduces FilterCapsuleQueue bean with a narrow API (offer, timed poll; stream() is test-only). Manager posts block/log filters to it, so it no longer references org.tron.core.services.jsonrpc. Drops unreachable offer-failure handling since the queue is unbounded.
  • Moves the filter consumer loop into TronJsonRpcImpl; starts at @PostConstruct only when isJsonRpcFilterEnabled(), runs in a single daemon thread, exits on interrupt, warns on unknown FilterTriggerCapsule subtypes.
  • Makes TronJsonRpcImpl.close() idempotent and stops the consumer before logsFilterPool; an interrupted closer returns while preserving the interrupt status and keeps logsFilterPool open until the consumer exits so an in-flight over-threshold capsule is not rejected. ApplicationImpl.shutdown() closes TronJsonRpcImpl after producers stop and before dbManager.close(), logging any close failures.
  • Adds end-to-end delivery (full/solidity and reorg paths), consumer lifecycle (disabled mode, interrupt, interrupted closer, context destruction, repeated close), and shutdown-race tests; updates existing tests to the new constructor.

Migration

  • Replace direct constructions with new TronJsonRpcImpl(nodeInfoService, wallet, manager) and remove setManager(...) calls.
  • If code inspected the filter queue directly, inject FilterCapsuleQueue and use offer(...); for tests, use its stream() accessor.