Skip to content

saveEventually / EventuallyQueue doesn't work when killing server -> saveEventually object -> restarting server #2028

@mortenmo

Description

@mortenmo

New Issue Checklist

Issue Description

Loading an object in client, then calling saveEventually on it after killing the parseserver, then starting it up again doesn't work for me. It seems to be a few different issues. Maybe I'm just doing something really wrong, and if so I'm sorry in advance :)

Test code is really simple. I find object "Foo" (with server up) in the console, kill server, client executes this code:

result[0].set("counter", result[0].get("counter")+1); await result[0].saveEventually(); 

I can see the Parse.EventuallyQueue.getQueue() have the following

'[{"queueId":"save_Foo_T6r7uWTcU9_","action":"save","object":{"counter":13,"createdAt":"2023-09-22T16:00:06.541Z","updatedAt":"2023-09-22T18:48:30.396Z","ACL":{"G2lwffEEaD":{"read":true,"write":true}},"objectId":"T6r7uWTcU9"},"serverOptions":{},"id":"T6r7uWTcU9","className":"Foo","createdAt":"2023-09-22T18:48:44.083Z"}]

When I restart the server, I don't see any attempts to save to server but queue is empty. It seems to fail this test in EventuallyQueue.sendQueueCallback under save:

// Queued update was overwritten by other request. Do not save
      if (
        typeof object.updatedAt !== 'undefined' &&
          object.updatedAt > new Date(queueObject.object.createdAt)
      )

The code is checking is the object's updatedAt is greater than the object's createdAt, which will always be the case. My guess was that this should be object.updatedAt > queueObject.createdAt (when the queue object was created not the original object). hacking on the JS code did get me past this problem but it still wouldn't save.

Next issue is that the EventuallyQueue stores a .toJSON of my object, which includes among other things the ACL object.

With some extra logging, the ParseObject.save gets sent that ACL object. It fails on ParseObject.validate(attrs) (silently) with this:

Error: ACL must be a Parse ACL.
    at ParseObjectSubclass.value (ParseObject.js:1259:16)
    at ParseObjectSubclass.value (ParseObject.js:1578:31)
    at EventuallyQueue.js:386:27

I'm not sure here if the best fix is to delete the ACL out of the json stored in EventuallyQueue or if ParseObject.validate should allow for JSON versions of the ACL, but it does fail my very simple saveEventually regardless.

I don't normally modify ACLs on client, only server using save hooks, but taking them out would be one thing.

Another fix (although still would fail with ACLs changed on client) is to not do (in EventuallyQueue.enqueue):

 queueData[index] = {
      queueId,
      action,
      object: object.toJSON(), // <-- This stores ACL in json format..
      serverOptions,
      id: object.id,
      className: object.className,
      hash: object.get('hash'),
      createdAt: new Date(),
    };

Instead of object being the entire toJSON() storing only the values of the changed keys (_getSaveJSON() ?). Or maybe change the ACL object if present back into a valid version.

Steps to reproduce

Actual Outcome

Data is lost

Expected Outcome

Expected data to be saved when server starts up again.

Environment

Server

  • Parse Server version: 5.2.3
  • Operating system: OSX
  • Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): Local

Database

  • System (MongoDB or Postgres): MongoDB
  • Database version: 5.5
  • Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): local

Client

  • Parse JS SDK version: 4.1.0

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:bugImpaired feature or lacking behavior that is likely assumed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions