feat(event): run native queue and event plugin simultaneously#6852
feat(event): run native queue and event plugin simultaneously#6852h45hc47 wants to merge 1 commit into
Conversation
| this.triggerConfigList = config.getTriggerConfigList(); | ||
|
|
||
| useNativeQueue = config.isUseNativeQueue(); | ||
| useEventPlugin = StringUtils.hasText(config.getPluginPath()); |
There was a problem hiding this comment.
[SHOULD] @h45hc47, switching the "plugin enabled" condition from !useNativeQueue to "path is non-empty" introduces an upgrade regression: a node currently running with useNativeQueue = true that happens to still have a non-empty path in its config (the old docs said path is ignored when useNativeQueue = true, so such leftover config does exist) boots fine today as native-only; after the upgrade it will try to load that plugin because useEventPlugin = true, and if the plugin zip is missing/invalid, launchEventPlugin returns false -> start() returns false -> Manager.startEventSubscribing() throws TronError(EVENT_SUBSCRIBE_INIT), so the node fails to start outright.
Overall I'd recommend keeping the current behavior (native queue and plugin mutually exclusive); the existing design is fine as-is:
- The "deliver to both" need can be solved cleanly outside the node: enable the native ZMQ queue and run a lightweight consumer that subscribes to ZMQ and persists to MongoDB. The node keeps a single sink and minimal responsibility, instead of coupling dual delivery into the core.
- Mutual exclusivity is a safety property here, not a defect: it keeps plugin/MongoDB failures out of the node, so a failed plugin load or a MongoDB outage cannot affect the block-producing node. This PR removes that isolation (the startup failure above is the direct consequence) and also couples the plugin queue's back-pressure into the block-loading path (
HistoryEventService/BlockEventLoadstart throttling on the plugin queue even when the native queue is on), adding failure surface and coupling to a subsystem that is sensitive to block processing. - The trade-off doesn't pay off: the benefit is a niche scenario that already has a clean external alternative, while the cost is added coupling in a core subsystem, a new failure path that can prevent the node from starting, and the per-trigger overhead of an extra serialization plus dual dispatch on a hot path.
So I'd suggest not merging this for now and keeping the current mutually-exclusive semantics. If there's a strong need later, it should be redone as an explicit opt-in flag that guarantees zero behavior change for existing configs.
There was a problem hiding this comment.
Agree with this compatibility concern. If we still want to support the dual-sink use case, I think it should be behind an explicit opt-in flag so existing native-queue configs keep the old behavior even when path is non-empty.
It would also be good to add regression tests for:
useNativeQueue=true+ stale/nonexistentpathshould still start as native-only unless dual-sink is explicitly enabled.- explicit dual-sink mode starts both sinks and dispatches each trigger to both.
- Plugin startup failure behavior is defined for dual-sink mode.
What does this PR do?
Makes the native ZMQ message queue and the event plugin (e.g. the MongoDB plugin) two independent event sinks, so a node can publish triggers to both at the same time.
Previously they were mutually exclusive: when
useNativeQueue = true, the plugin'spath/server/dbconfigwere never loaded and only the native queue started; the plugin only ran whenuseNativeQueue = false.Key changes:
Args: always copypath/server/dbconfigintoEventPluginConfig, regardless ofuseNativeQueue.EventPluginLoader: add a separateuseEventPluginflag (derived from a non-empty plugin path).start()launches the plugin first — so the plugin's listeners exist before any topic is registered — and then the native queue. Eachpost*Triggeris dispatched to every active sink;setPluginTopicis null-guarded for the now-possible double trigger-config pass;isBusy()is gated on the plugin being active instead of on the native queue being off.HistoryEventService: honor the plugin's back-pressure (isBusy) during historical sync even when the native queue is enabled, so the plugin queue is not flooded. Native-only pacing is unchanged.config.conf/reference.conf: document thatuseNativeQueueand a pluginpathcan be combined.Why are these changes required?
Operators often want both transports at once: low-latency ZMQ delivery for real-time consumers AND durable persistence in MongoDB for querying and indexing. Today they must pick one. With a single
event.subscribeblock (native queue on + a plugin path set), both now receive every trigger.Example configuration enabling both:
This PR has been tested by:
:commonand:frameworkcompileJavasucceed.EventPluginLoaderTest#testIsBusy— updated for the newuseEventPluginsemantics — PASSED.HistoryEventServiceTest#test— covers the reordered back-pressure path — PASSED.useNativeQueue = trueand a MongoDB plugin path set starts cleanly, writes events to the MongoDB collections, and binds the native ZMQ queue on port 5555 simultaneously.Follow up
A future enhancement could add an explicit
useEventPluginconfig key instead of inferring plugin activation from a non-emptypath.Extra details
In combined mode the trigger-config pass runs once per launcher; this is idempotent (boolean flags and
setTopicoverwrite with the same values). Every trigger is now serialized and dispatched to both sinks, a modest overhead versus single-sink mode. Behavior is unchanged for the two existing single-sink configurations (native-only, or plugin-only).