Skip to content

fix(iot-dev): Fix race condition where reconnection logic could carry on after client was closed#1356

Merged
timtay-microsoft merged 3 commits intomasterfrom
timtay/raceCondition
Sep 14, 2021
Merged

fix(iot-dev): Fix race condition where reconnection logic could carry on after client was closed#1356
timtay-microsoft merged 3 commits intomasterfrom
timtay/raceCondition

Conversation

@timtay-microsoft
Copy link
Copy Markdown
Member

If close is called during reconnection, it will block until the current reconnection attempt completes (successfully or not) before closing the connection and marking the local state as closed

If reconnection is initiated during a close, it will block until the close call has finished tearing down the connection and marking the local state as closed. After the close call has finished, the reconnection logic will immediately give up since the client was closed

#1343

… on after client was closed

If close is called during reconnection, it will block until the current reconnection attempt completes (successfully or not) before closing the connection and marking the local state as closed

If reconnection is initiated during a close, it will block until the close call has finished tearing down the connection and marking the local state as closed. After the close call has finished, the reconnection logic will immediately give up since the client was closed
&& transportException != null
&& transportException.isRetryable())
{
if (this.isClosing)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check occurs in the reconnection loop, so if close() is called while this reconnection is already happening, it will block until the latest reconnection attempt completes and the thread exits before the close() call continues.

throw new TransportException("Open cannot be called while transport is reconnecting");
}

this.isClosing = false;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag is reset to false every time the transport is opened

}

this.cancelPendingPackets();
this.isClosing = true;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set the flag outside of the synchronized block so that any currently running reconnection logic knows to give up when this flag is set to true. Then the rest of the close() code is in the synchronization block so that it waits for the reconnection logic to end before it starts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a good code comment

@timtay-microsoft
Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 4 pipeline(s).


if (this.taskScheduler != null)
// Wait until no reconnection logic is taking place
synchronized (this.reconnectionLock)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having locks within a lock makes me worried about deadlocks. Thoughts?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to the sendThreadLock and receiveThreadLock? Neither of those locks are acquired or modified in the reconnection thread. There is no chance that the reconnection thread holds onto the sendThreadLock or receiveThreadLock while the close() thread holds the reconnectionLock so we're safe from deadlock

@timtay-microsoft
Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 4 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants