[ 
https://issues.apache.org/jira/browse/NIFI-16308?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Mark Payne updated NIFI-16308:
------------------------------
    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.


  was:
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.


> 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
>            Priority: Major
>
> 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.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to