I just figure out the hard way that apparently even on the server side, some collection update calls are non-blocking, namely when they are not called through a Meteor.method() definition. What I mean by that is that in the code immediately following the collection.update() call, the data is still the old data, which is a clear sign the db update runs in the background and the update() call returned anyway. I can confirm this by adding a callback function and I find that inside the callback, the data is updated.
I am defining a couple of backend maintenance functions, defined inside a service class and called by shell or cron job. These functions are not and should not be called remotely, so they are not defined as Meteor methods. But they are in a server-only directory (/imports/server/)
Turns out they return immediately and don’t block until the database writes are complete. I verified this.
That is pretty… wrong for my use case. I want them to block. How do I force them to do so?
If you use the non-callback (Promise) form of the standard npm MongoDB package, you could make use of async/await to ensure that your changes happen synchronously. They will never be strictly blocking. I don’t believe there’s a blocking version of the MongoDB package - that would be a tad crazy .
I am working entirely in Meteor. I just have maintenance methods that are not triggered by a client. Think “nightly cleanup”. At the moment I call them through the Meteor shell. In production, they will be called by a job.
I’m doing my update via the Meteor collection, e.g.
let collection = new Mongo.Collection('something')
...
class Service {
static someFunction() {
collection.update(id, { $set: { ... } })
}
}
In which case I’m not sure what you mean by “blocking”. In NodeJS that refers to blocking the event loop, which can be done for some operations, but not MongoDB AFAIK.
If you just want to prevent other access to the database, or collection(s), I suspect the best you’ll be able to do is set a global flag somewhere (in MongoDB itself, perhaps) that all other processes check before doing something.
what I mean is that after the update call, the data is not immediately updated. The call doesn’t block, it returns and the db update happens in the background, despite the Meteor documentation saying that server-side db updates should block.
I don’t mind if other processes access the db as well. I just need to continue working with the data after the update, and I can’t because I cannot be certain it has been updated already.
updates the database, but it does not update the in-memory collection. It does correctly return the number of updated records. All this this looks quite odd behaviour to me. A bug, maybe? Or is my collection copied somewhere in a function call (the “warehouse” variable is passed through several function calls, but it should be an object, namely one element of the collection)
warehouse = ...findOne()
...do some calculations...
Warehouses.update()
...do some other calculations...
Warehouses.update()
in the 2nd (3rd, etc.) round of calculations, I’m still working with the old data. Re-fetching updated entities is the workaround I’m now using. It would be very cute if Meteor would ensure that my in-memory copy would also change when I update the database. After all, that’s what I thought would happen when I update through the collection instead of through raw Mongo calls.