Answer the question
In order to leave comments, you need to log in
How to synchronize objects in a multi-threaded application on node.js?
Game server on nodejs (tcp packages, base - mongo, game logic - to a minimum).
"Player" is an object with resources (gold, silver, things, etc.). When the client connects to the server, I find the player in the database or in the cache, and until the moment of disconnection, the player "belongs" to this connection.
So far, I just started writing, but there is a desire to use cluster, so that in the future I don’t suffer with scaling.
And the question immediately arises - how to beautifully organize the exchange of resources between players in different workers?
The simplest situation when it is needed:
2 players connect to the server (Zhenya and Masha), their connections are processed by different workers. A package arrives from Zhenya's client: "I want to buy 5 'sheep' objects from Masha for 15 gold pieces."
How to take away 5 sheep from Masha and give her 15 gold, and vice versa from Zhenya, taking into account validation, saving in the database, a possible sudden stop of the server, etc.?
Internet search did not give anything special: at best, articles at the level of "Created a worker, sent a message."
So far I see these options:
'use strict';
class MarkedValue
{
constructor(value)
{
this.innerValue = value;
this.reserved = new Map();
this.appended = new Map();
this.reservedSum = 0;
}
get value()
{
return this.innerValue - this.reservedSum;
}
reserve(transactionId, amount)
{
if (this.value < amount)
return false;
if (this.reserved.has(transactionId))
this.reserved.set(transactionId, this.reserved.get(transactionId) + amount);
else
this.reserved.set(transactionId, amount);
this.reservedSum += amount;
return true;
}
append(transactionId, amount)
{
if (amount <= 0)
return false;
if (this.appended.has(transactionId))
this.appended.set(transactionId, this.appended.get(transactionId) + amount);
else
this.appended.set(transactionId, amount);
return true;
}
apply(transactionId)
{
let reservedAmount = this.reserved.get(transactionId);
if (reservedAmount !== undefined)
{
this.reservedSum -= reservedAmount;
this.innerValue -= reservedAmount;
this.reserved.delete(transactionId);
}
let appendedAmount = this.appended.get(transactionId);
if (appendedAmount !== undefined)
{
this.innerValue += appendedAmount;
this.appended.delete(transactionId);
}
}
rollback(transactionId)
{
let reservedAmount = this.reserved.get(transactionId);
if (reservedAmount !== undefined)
{
this.reservedSum -= reservedAmount;
this.reserved.delete(transactionId);
}
this.appended.delete(transactionId);
}
}
module.exports = MarkedValue;
Answer the question
In order to leave comments, you need to log in
Believe me, you will not hit the base for a very long time, especially in monga. So what can be done in the easiest way.
A good solution would be to have a common storage in memory (radish, memcache), and yes, you have to serialize, etc., there are no simple and quick solutions to such problems. If you are interested in interprocess communication, then there is process.send / process.on('message') for this, but this is only available for processes of the master<->child type, and I do not advise you to abuse it, with intensive exchange it will be bad for both the OS and your application.
Create a transaction, change the data in the database.
I see no problems with speed (within the same reliability) and inconvenience. The method is the most convenient and reliable.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question