Mark Payne created NIFI-16308:
---------------------------------
Summary: StandardConnectorNode can schedule duplicate concurrent
starts
Key: NIFI-16308
URL: https://issues.apache.org/jira/browse/NIFI-16308
Project: Apache NiFi
Issue Type: Bug
Reporter: Mark Payne
h2. Description
StandardConnectorNode.start() reads the current Connector state and then
unconditionally sets it to STARTING. When two callers start the same Connector
concurrently, both can observe STOPPED and both can schedule startComponent().
The second state update is logged as STARTING -> STARTING.
This was observed while validating the Connector mock framework against the
Kafka-to-S3 Connector. ConnectorTestRunner.applyUpdate() initiated an
asynchronous stop and returned. An immediate explicit start set the desired
state to RUNNING. When the stop completed, StandardConnectorNode also initiated
its automatic restart, allowing both start calls to proceed concurrently.
h2. Reproduction
# Begin an asynchronous Connector stop.
# Request start while the current state is STOPPING, setting the desired state
to RUNNING.
# Allow stopComponent() to reach STOPPED and invoke its automatic restart.
# Arrange for the explicit start and automatic restart to complete validation
together.
# Observe both callers read STOPPED, followed by STOPPED -> STARTING and
STARTING -> STARTING transitions.
h2. Impact
Both calls invoke Connector.start() and attempt to start the same managed
processors and controller services. The first path can reach RUNNING while the
duplicate path is refused because components are already STARTING. Completion
futures created for the duplicate processor starts may never complete, which
can strand the associated Connector start Future even though the Connector is
running. Callers that wait on that Future can hang or time out, and Connector
lifecycle callbacks can execute concurrently.
h2. Proposed Correction
Use an atomic compare-and-set loop when transitioning an eligible state to
STARTING. A caller that loses the transition should re-read the state and
register its Future as pending instead of scheduling another component start.
Pending-start registration must also be atomic with the transition to RUNNING
so a Future cannot be registered immediately after pending futures have already
been completed.
Add a deterministic concurrency regression that releases two start requests
after both have entered validation, then verifies Connector.start() is invoked
once and both returned Futures complete.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)