-
Notifications
You must be signed in to change notification settings - Fork 31
STITCH-1950 Add collection level sync configuration #67
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
Conversation
Seems like some formatting got included in this PR. I can remove it, or we can keep it if we want. |
Evg is being flakey. Otherwise this is ready for review. The driveby tab changes are valid, however, I can move them to another PR if we feel that it's here inappropriately. |
"mongodb", | ||
"mongodb1", | ||
ServiceConfigs.Mongo(getMongoDbUri())) | ||
app.second, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove the reformats to avoid conflicts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with first pass
); | ||
this.triggerListeningToNamespace(namespace); | ||
|
||
if (!this.isConfigured) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] We should grab the lock first before checking configured otherwise this can be a torn read or write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
...ain/java/com/mongodb/stitch/core/services/mongodb/remote/sync/internal/DataSynchronizer.java
Show resolved
Hide resolved
(remoteEvent.getFullDocument() == null && resolvedDocument == null) | ||
|| (remoteEvent.getFullDocument() != null | ||
&& transformedRemoteEvent.getFullDocument().equals(resolvedDocument)); | ||
&& remoteEvent.getFullDocument().equals(resolvedDocument)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[major] This is reintroducing a bug. Please undo any reformats or changes unrelated to this ticket in this PR.
...ain/java/com/mongodb/stitch/core/services/mongodb/remote/sync/internal/DataSynchronizer.java
Show resolved
Hide resolved
val docToInsert = Document("hello", "world") | ||
testSync.insertOneAndSync(docToInsert) | ||
|
||
assertFalse((mongoClient as RemoteMongoClientImpl).dataSynchronizer.isRunning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[test] Instead of needing an isRunning as var and exposed, you can instead just add a semaphore to watch a change stream come in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* | ||
* @return true if configured, false if not | ||
*/ | ||
boolean isConfigured() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] must be synchronized
fun testConfigure() { | ||
val testSync = getTestSync() | ||
|
||
(mongoClient as RemoteMongoClientImpl).dataSynchronizer.enableSyncThread() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite positive, but it seems like the expose and implementation of .enableSyncThread()
is not strictly necessary. You can use manual sync passes if you need to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. This makes more sense. It will slightly change the tests, but yes, if we address your comment below, we can remove the enableSyncThread
method.
} | ||
} | ||
|
||
public void enableSyncThread() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] Think this can be deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having this here allows us to check that the thread is started from within our tests.
), | ||
"mongodblocal", | ||
ServerEmbeddedMongoClientFactory.getInstance() | ||
StitchAppClientInfo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this file can be reverted.
val bsonCodec = BsonDocumentCodec() | ||
|
||
// fetch a new namespace, creating a new config | ||
val nsConfig: NamespaceSynchronizationConfig = dataSynchronizer.getNamespaceConfig(namespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] I think you can get rid of dataSynchronizer.getNamespaceConfig
and getNamespaceConfig
as being exposed. Instead you should be able to utilize the top level public methods on the data synchronizer instead to act as a normal consumer which would make this a stronger test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might it make more sense to do that in an integration test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. The unit test here is aiming to check what happens if you are to configure twice. The first configuration should end up starting the listener. We don't need to reach that far into the implementation details. It ends up making the test brittle and not covering the actual aspect you want to test via the public API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just one nit (that affects a bunch of places), but otherwise looks I good I think once you make Eric's changes
*/ | ||
void configure(final ConflictHandler<DocumentT> conflictHandler, | ||
void configure(@NonNull final ConflictHandler<DocumentT> conflictHandler, | ||
final ChangeEventListener<DocumentT> changeEventListener, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] if we're labeling the conflict handler @NonNull
, I guess we should explicitly mark the rest as @Nullable
?
|
||
@Override | ||
public void configure(final ConflictHandler<DocumentT> conflictHandler, | ||
public void configure(@NonNull final ConflictHandler<DocumentT> conflictHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
* @param errorListener the error listener to invoke when an irrecoverable error occurs | ||
*/ | ||
void configure(final ConflictHandler<DocumentT> conflictResolver, | ||
void configure(@Nonnull final ConflictHandler<DocumentT> conflictHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
|
||
@Override | ||
public void configure(final ConflictHandler<DocumentT> conflictResolver, | ||
public void configure(@Nonnull final ConflictHandler<DocumentT> conflictHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
public <T> void configure(final MongoNamespace namespace, | ||
final ConflictHandler<T> conflictHandler, | ||
public <T> void configure(@Nonnull final MongoNamespace namespace, | ||
@Nonnull final ConflictHandler<T> conflictHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
* during data synchronization | ||
*/ | ||
void configure(final ConflictHandler<DocumentT> conflictResolver, | ||
void configure(@Nonnull final ConflictHandler<DocumentT> conflictResolver, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
|
||
@Override | ||
public void configure(final ConflictHandler<DocumentT> conflictResolver, | ||
public void configure(@Nonnull final ConflictHandler<DocumentT> conflictResolver, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One comment and one offline comment. Other than that LGTM
Notes: I've handled the possible null case here in what I felt was best for usability, however, it may need to be agreed upon.
Description:
Configuration for sync happens at collection.sync().configure() where configure is: configure(, , ). See spec for more info.
This configure should be the signal to the data synchronizer to start synchronzing if it hasn't already. Subsequent configurations just update handlers and listeners. The signal is to prevent an error condition where we were to sync but do not know how to handle conflcits since a handler has not been set up yet. Most app code will always be calling configure first.