Skip to content

Receiving Subscription Update Events Before Uploader Has a Chance to Finish Uploading #12

Open

Description

@timarnold

Howdy!

I've really been enjoying the book and the sync codebase, and am building off it for our own project.

I'm building a remote type that uses Firebase instead of CloudKit. One thing I encountered is the following:

  1. Object A created locally, recognized by Uploader Change Processor. Object A has a nil remoteIdentifier until it is successfully uploaded
  2. Upload begins
  3. Upload succeeds, but the completion block has not been fired and our app has not yet been notified of a successful upload
  4. Object Added Change Subscription from Firebase notifies the app that we have a new object that was added to the remote destination
  5. App adds the object from step (4) to the local store
  6. Successful upload from step (2) returns to app, and remoteIdentifier is assigned to the local object created in step (1)

Expected result: we should have one object that has been successfully stored in the remote destination

Actual result: we have created two local objects with identical remoteIdentifier values, and there is one object at the remote destination.

I'm not sure this scenario is possible with the Moody sample app, or with CloudKit at all, because of the way remote push updates work with CloudKit. But with the way I added Firebase subscriptions / push updates, it's definitely happening for me.

Is this a scenario you contemplated or experienced at all during your work on the sample app? Do you have any ideas about how this could be avoided?

Activity

  1. danieleggert commented on Mar 14, 2016

    @danieleggert

    Hi @timcamber — yes, that complicates things. We didn't anticipate this Cloud Kit behaviour.

    What does the Object Added Change Subscription look like? Is there anything in there that lets you know that the addition originates from that very same device?

  2. timarnold commented on Mar 14, 2016

    @timarnold
    Author

    I'm not a Firebase expert, but I don't think there's inherently information about the origin of the objects coming from the remote destination. Of course we could add this --- I had not thought of adding something like a UDID to model objects. That might be the simplest way to solve this. The only other thing I had thought of was to have a separate object identifier (in fact, our app already has this, so it was a simple quick fix), and not to merge in objects from the subscription if the object already exists locally. I think using a UDID is a better fix.

    My subscription with Firebase is set up using their observeEventType(_: FEventType, withBlock: (FDataSnapshot) -> Void ) function, which simply sends an FDataSnapshot object to the closure whenever an update occurs. FDataSnapshot, as far as I can tell, doesn't tell me anything about how it came to be or where it came from.

    Edit: in case it's helpful, here is where I set up my subscription (Tasks instead of Moods, and I have tweaked the Remote protocol to accommodate this):

    func setupTaskSubscription(updateHandler: ([RemoteRecordChange<RemoteTask>]) -> Void) {
        tasksReference.observeEventType(.ChildAdded) { (snapshot: FDataSnapshot!) -> Void in
            if let contents = snapshot.value as? [String:AnyObject],
                let updatedTask = RemoteTask(record: FirebaseRecord(contents: contents, recordID: snapshot.key)) {
                    updateHandler([.Insert(updatedTask)])
            } else {
                updateHandler([])
            }
        }
    }
    

    which is invoked in, e.g., my TaskDownloader, like so:

    func setupForContext(context: ChangeProcessorContextType) {
        context.remote.setupTaskSubscription { (changes: [RemoteRecordChange<RemoteTask>]) -> Void in
            self.processChangedRemoteObjects(changes, context: context, completion: { _ in })
        }
    }
    

    Other than these changes, much of my implementation is the same as in your example.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions