I have a side project I have been working on for a while now that involves a React Native mobile app, some node services and a cloud platform (MetaApi) that hosts MetaTrader trading accounts on to permit API based accessed to the trading account data over REST. Recently I have started looking at setting up a real-time data notification service using the web-socket capabilities of the SDK which is a fairly new concept to me.
The challenge that I am facing currently is that for each hosted trading account on the cloud platform, a client socket connection must be established on the notification node service that is kept alive 24/7, and must have event listener actions applied to it in order to receive live data for that account and use this data to trigger actions for example a push notification. Having worked with web-sockets before (socket.io) the challenge here is that for real-time data to be listened to 24/7 for the use-case of a notification service, the client connections are required to be established and persisted on the node notification server, rather than a users device for example where the connection is only required to be established and maintained during the the user session.
I'm unsure on this approach for a couple of reasons:
- It seems like initialising and referencing potentially hundreds of client socket connections in memory is going to be terrible for resource consumption and scaling
- Failover, if the service running with these client connections on suffers a downtime, all of these connections are lost and must be reinitialised
Is there an approach that I can adopt in this scenario that would make handling this better? At the moment I am considering abandoning this approach to a notification service with the cloud platforms SDK for web-sockets, and instead falling back to perhaps to a polling approach to trigger notifications based on changes in responses utilising the REST API, though not ideal.
I've added some code below that I've been playing with as a reference to how this is being implemented currently on the notification server startup
// Fetch deployed trading accounts from the cloud platform
const fetchAccountsWithSDK = async (limit = 100, offset = 0) =>
api.metatraderAccountApi.getAccounts({
limit,
offset,
state: ["DEPLOYED"],
});
// call fetchAccountsWithSDK to build up an array of all deployed accounts?
const getDeployedAccounts = async () => {
const limit = 100;
const accounts = [];
const fetch = async (offset = 0) => {
const fetched = await fetchAccountsWithSDK(limit, offset);
accounts.push(...fetched);
// If the fetched count = the limit, call again to fetch further accounts
if (fetched.length === limit) return fetch(accounts.length);
// Returns array of all accounts
return accounts;
};
// Return fetched accounts, starting at offset 0
return fetch(0);
};
const initAllAccounts = async () => {
// Use the SDK to get all currently deployed trading accounts on the cloud platform
const deployedAccounts = await getDeployedAccounts();
// Create an array of connection references for deployed trading accounts
const accountConnections = await Promise.all(
deployedAccounts.map(async (item) => {
// Initiate a connection with the trading account
const connectedAccount = await item.connect();
// Synchronise data from the trading account
await connectedAccount.waitSynchronized();
// Initialise event listener actions for trading account connection
const AccountListeners = new Listeners({ accountId: item._data._id });
// Apply event listener actions to the trading account connection
connectedAccount.addSynchronizationListener(AccountListeners);
// Return an object containing the accountId and a reference to the connection
return { accountId: item._data._id, connection: connectedAccount };
})
);
// Not sure what do with accountConnections array
// but a reference needs to be kept somewhere, i.e. if the connection is to be closed due to user closing account(connection.close())
};
// initialise web-socket client connections for all trading accounts and apply socket event listener actions
initAllAccounts();
Here's some sample code of the listeners that are applied to each connection for my use-case:
class Listeners extends SynchronizationListener {
constructor({ accountId = "" }) {
super();
// Assign reference of account id event is for, use in following actions
this.id = accountId;
}
async onDisconnected() {
// handle account disconnected from trading terminal action here
}
async onConnected() {
// handle account connection action here
}
async onAccountInformationUpdated(accountInformation) {
// handle account information updated here i.e. triggering push notification that trading balance has changed etc
}
}
question from:
https://stackoverflow.com/questions/65862313/managing-web-socket-client-connections-on-a-node-service-for-real-time-notificat 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…