How does Firebase atomic increment work in race condition? - javascript

Firebase atomic increment can be used in update or set. But they don't return the updated value on completion. So, I have to use once('value') immediately after update or set:
var submitref = firebase.database().ref('/sequence/mykey')
return submitref.set(firebase.database.ServerValue.increment(1)).then(_=>{
return submitref.once('value').then(snap=>snap.val());
});
Lets assume 2 threads are executing this code concurrently. submitref.set() will work fine, because of atomic increment. But if they complete submitref.set() at the same time and execute submitref.once('value') at the same time, both threads will receive same incremented value by +2.
Is this a possibility or am I not understanding it correctly?

The increment operation executes atomically on the server. There is no guarantee in their operation that all clients (or even any client) will see all intermediate states.
Your use-case to keep a sequential, monotonically incremental counter is better suited to a transaction since with a transaction the client controls the new value based on the current value.

JavaScript is a single-threaded language. Every bit of code executes in some order relative to any other bit of code. There is no threading contention except through any native libraries, which is not the case here. Also, Realtime Database pipelines all of its operations over a single connection in the order they were received, so there is a consistent order to its operations as well.
All that said, I imagine you could get into a situation where the two calls to set() happen before the two calls to once(), which means they would both show the twice-incremented value.
In this case, you might be better off overall using a listener with on() in order to simply know the most recent value at any time, and act on it whenever it's seen to change, regardless of what happens after establishing it.

Related

Node.js write object propertys in same time via socket.io

In Node.js, can it happen that when different properties of a global object are written at the same time (with a socket.io request), one of the properties retains its original value?
`
var rooms = {
a: {
move: 1
},
b: {
move: 2
}
};
// it's called same time from different client with different room id
socket.on('onmove', function(data) {
var room = rooms[data.room_id];
room.move = data.move;
});
`
I tried to testing, but did not collide with each other.
However, I have an online game where the anomalies point to this.
The question is, is this theoretically possible? How are properties overwritten? Does one have an effect on the other?
Nodejs runs your Javascript in a single thread so no two requests are actually executing your Javascript at the exact same moment in time. So, the code you show, all by itself, will not be susceptible to a race condition.
The question is, is this theoretically possible?
No, not with just the code you show. The move event handler will run to completion before any other requests or events can get called.
How are properties overwritten? Does one have an effect on the other?
No. Assigning to one property does not affect other properties.
That said, there are certainly concurrency-related things to be aware of in nodejs, particularly if a request handler is doing something asynchronous. This is because, while it's waiting for some asynchronous completion callback to be called, other requests can run, change state, etc... So, if one request handler grabs some state, then does something asynchronous and expects that state not to change while it's waiting for the asynchronous callback to be called, then it could lead to concurrency issues because other request handlers can run during that time and can affect server-side state.
Plus, there are many database operations that need to be coded carefully to avoid concurrency issues since two requests could be trying to make conflicting changes to the database or one request handler could grab some data, modify and write it back while another request handler is doing the same thing causing one request's changes to get overwritten.
So, if you suspect that this code is somehow involved in a concurrency issue, then I'd suggest you disclose a lot more related code so we can see if the way you've written the rest of the related code could lead to concurrency issues.

Will a computed property stop computing if a dependency is updated during execution?

Lets say you have a computed property that filters and sorts an array of values based on a user's input.
If the user begin filtering values from the array, and the sorting value changes during the computation of the filtering, will the computed property continue the execution of the filtering, or will the computed property jump to the next calculation of the computed property in the queue, with the new sorting value?
Javascript is (essentially) single threaded. That means nothing can even process the fact that a user triggered event occurred until the currently executing synchronous code finishes executing.
You can do something yourself to emulate this, though. Add async pauses where you free up the run loop which allows events to be processed, and then resume and check some cancelation condition, then you may be able to achieve something like you're asking. But that's a lot of code, and unless that filtering is really slow, that's probably a bad idea.
Computed properties will completely finish execution.
If the old Vue.js v2 documentation still holds any relevance, then the following passage indicates how changes result in updates:
[...]Vue performs DOM updates asynchronously. Whenever a data change is observed, it will open a queue and buffer all the data changes that happen in the same event loop. If the same watcher is triggered multiple times, it will be pushed into the queue only once. This buffered de-duplication is important in avoiding unnecessary calculations and DOM manipulations. Then, in the next event loop “tick”, Vue flushes the queue and performs the actual (already de-duped) work.
Given JavaScript is a single-threaded language, this would mean that during any particular "tick" of the event loop, no other actions will be processed until the code execution during this "tick" has finished.
If hypothetically Vue's internal behavior were such that these updates were handled purely asynchronously, then there would be the potential for race conditions between any two event loop ticks, especially if the first tick takes a long time to complete while the second tick finishes quickly. Halting the execution of a computed property part way, even if it were possible, could also result in any side effects normally triggered by the computed property's execution (bad practice, but that's another subject) to not be triggered.
These inconsistencies in behavior would cause all kinds of problems for maintaining consistency in the application state, which is a problem that would make any reactive framework effectively worthless.

Javascript Asynchronous State Update

I'm trying to think the best practice for this use case:
I have an internal state: results[] that will be used for displaying data in render.
Then, I need to call 3 API's, in parallel, and then merge and sort them into results[] before finally rendering it.
I'm using axios to call the API's, but i don't want to use axios.all because i need to display the results[] as each of the 3 apis are returning, that way, it looks faster.
Im running into problem because everytime i update results[] with new data using this.setState(), the latter operation always see the old results[]; this.setState() doesn't immediately get applied..
What's the best way to do this?
There will never be a race condition since Javascript runs on a single thread. It is guaranteed that only one asynchronous callback will run at any one time, since a single thread cannot execute both at once. The next asynchronous callback will be scheduled to run later. Within one function call, you can be assured that you are the only one working on some data.
Data may come in at different times, but if you simply merge and sort the data every time you receive new data, that will be atomic.

What happens if you are simultaneously modifying an array that you are looping through in node js?

I'm new to node js and am just getting used to the asynchronous nature of the language...
I have a function that updates values in an array A every 60 seconds (grabs them from a database).
I also have a function that processes requests from users, and while processing these requests it uses values from A (and so I loop over A).
I'm wondering if this type of thing being asynchronous will crash my app?
For example if I'm in the middle of looping over A and grabbing values but at the same time, the 60 second timer hits and begins to update the values in A, can anything bad happen?
If so, do you have any design suggestions to avoid this?
Thank you very much for any help!
It really depends upon your exact code so no concrete answer can be provided without seeing and understanding your exact code.
Javascript in node.js is single threaded so if you are looping through an array with a synchronous mechanism such as .forEach() or a for loop, then any async calls you make will be initiated, but they cannot finish until after your current thread of execution (including the loop through the array) is completely done. So, no async result can impact the array while you are still looping.
There are less conventional and async ways to iterate through the array. If you were using one of those, we'd have to see your actual code to offer an opinion on whether you have any concurrency issues or not.
For example if I'm in the middle of looping over A and grabbing values
but at the same time, the 60 second timer hits and begins to update
the values in A, can anything bad happen?
node.js is event-driven. This means that when a timer is ready to fire, it inserts an event into the node.js event queue. That event will not be processed until the current running Javascript is done and the node.js JS engine can then pull the next event out of the event queue. So, a timer will not interrupt your current running Javascript, ever.
You may encounter weird bugs from doing this. If you are in the middle of A and A gets much shorter, it will terminate the loop. For example suppose that A has 30 elements. While you are looping though, it gets changed to length 15 when you are on index 16. It would not continue looping. Another example. Suppose that A has length 2. When you finish the stuff for the first index, when you go to the second, the value of both indexes gets changed, then the first one would be reported as the old value, and the second one as the new value.

Does nodejs make separate database operations in a single function as atomic?

I've been trying to write some database queries that run on node js, and this came up to my mind. I can smell I'm misunderstanding something, but can't figure it out what it is.
If node is single-threaded, then this means all function calls run one after another. If there are multiple clients accessing the same node server, there will still be a race in which request gets queued first, but as long as each request is processed one by one, doesn't this make all database operations performed in a single request atomic?
For example, let's say I want to 1) count the number of columns matching some value in a table and 2) insert a new row if the number is more than 10. (It is probably possible to do this in one SQL query, but let's assume I run them separately. It's a dumb example, but I hope you get the point.) I'd use a transaction to make sure the number of matching columns do not change unexpectedly. Now, I'm thinking to write a function that runs the two queries without a transaction. Would that guarantee to work properly on node?
I suppose you want to run your first call, a count, then you want to execute an insert in the callback of the previous call.
Because of the nature of js and thus of nodejs, once you are waiting for the response to the first call, once it is come back and put on the event loop (so, the count is gone, you already have the result on the fly), while waiting to be served, everything else can happen... Even another insert somewhere else could be served, why not (let me say, you are serving user requests, so an insert due to a request of another user, not the one that is executing the count).
That said, the insert of the second user could be served before the one sent after the count of the first user and that means that the insert bound to the count is working on a wrong expected size of the dataset.
That's only one of the possible cases you can incur in, but it should be enough to solve your doubts.

Categories

Resources