-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add experimental support for peer-to-peer updates #595
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This reverts commit 2b4e3ac.
the lodash.isMatch function we are using will match an empty array against any array, so to check the state is an empty array, we need to use the compare function to strictly check the array length.
I identified 2 bugs in my own QA testing:
These bugs are fixed now in this PR, and there are more comprehensive tests for the "checkedPeers" functionality. |
* develop: chore: Update instructions on NDK version in contributing docs chore: Update current NDK version in docs
Merged
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR started as an attempt to add strict TypeScript type-checking to this code, but that work resulted in identifying several bugs and some issues with the existing architecture that created many opportunities for race conditions.
This is a really complicated piece of code, with some complicated logic for managing peers appearing and disappearing from a local network. It's important that we can know it works reliably, but also the code needs to be well documented and easy to maintain by the entire team. This PR attempts to address that.
In general I've found that writing this with Typescript and async / await has resulted in much faster development - the code here took about 25 hours to write (excluding thinking time away from the computer) and it should be easier and quicker to add features and fix bugs.
Typescript
Everything is strictly typed now.
State Management
We were using the module
rwlock
to manage async state management. The main async state that we need to maintain is that the service can start and stop many times (because the user can navigate to and from the sync screen, or close and re-open the app) and the start and stop functions can be async. The use ofrwlock
meant that thestarting
andclosing
states were hidden.I created an abstraction,
AsyncService
, which manages start and stop of an async service according to tested rules. This means that we can test this complex code and simplify the code where the upgrade logic lies.async / await
Using callbacks with code that has so many async actions makes it hard to follow what is happening and catch race conditions. I have changed all the code to use async / await patterns, which I think makes the code easier to follow and maintain by avoiding nested callbacks and ensuring that the code flow is the same as the logic flow (top-to-bottom).
State complexity
The shape of the
state
emitted by the UpgradeManager was complex, which resulted in a lot of code to decide what state to show to the user in the UX. The main things that the UX needs to know are:This PR simplifies the state to just capture that information, it is documented in
lib/types.d.js
asUpgradeState
Code documentation
It's really important that this code is easy for others on the team to understand and maintain. It took me quite a while to parse the original code, so I have written many comments to explain why the code is written the way it is. I have also tried to be really clear about what are public methods and what methods are private (e.g. internal to the implementation and not something to be tested or used outside each class), with explanations of what each class and method does. I have used JSDoc format for comments, extended with Typescript annotations.
Server
Storage
startFinishStream()
and thoroughly tested it.Discovery
Evaluating potential upgrades
We had several places for comparing and evaluating upgrades. I tried to move all this logic into testable utility functions, with two separate tests:
This should make it easier to add additional logic for selecting a suitable upgrade candidate.
Next Steps
I really hope that these changes make this code more reliable and easier to maintain in the future.
There are a few tasks remaining (with estimated time):
server.js
(1h)_name
to#name
feat: Add experimental support for peer-to-peer updates #595 (comment) (1h) - non-essential choreWhen complete this code should close these issues: #589, #585, #576, #562, #559, #537