I'm using rawCollection().aggregate() to temporarily clone fairly large MongoDB collections from within Meteor. The original collections hold financial data continually updated from websocket, and the copies are to be used for backtesting that data on the fly while the master data continues to update every minute from websocket.
The concept works, and will clone a collection of ~1.2 million records (~1.2gb) in anywhere between 30 and 60 seconds. Smaller collections (50,000 records) are instantaneous.
The problem: once complete, the await resolves and copied records are present and can be counted, but Meteor remains frozen. The front end does not load new pages, the datatables and live price updates stall, and the server console stops logging. After ~ 7 minutes all frees up again, and data which has been brought in during the freeze is processed, and datatables update again. The server console takes another ~2 minutes to catch up on logging.
The intent is that the app remain functional while backtesting goes on in the background - but this renders the front end useless for a significant period. Perhaps this is expected, but I had hoped that the aggregate approach would prevent the lock up. It completes quickly - but what is then causing the subsequent freeze?
Code is below. Any help at all appreciated.
A two-line method takes the Meteor.call, then calls:
async function startBacktest_async(exchange_id, datainterval) {
const removeOldData = await removeCollectionFromBacktest(exchange_id, datainterval);
if (removeOldData === true) {
console.log("Backtest: Existing data removed");
} else {
console.log("Backtest: No data removed");
};
if (removeOldData) {
const collectionForCopy = data_collections[exchange_id + datainterval];
const copyCollectionCount = await copyCollectionForBacktest(exchange_id, datainterval, collectionForCopy);
if (copyCollectionCount) {
console.log("Backtest copy: Collection " + exchange_id + datainterval + " || " + copyCollectionCount + " records copied");
const copiedCollection = data_collections[exchange_id + datainterval + "_Backtest"];
// DO STUFF HERE
return "Backtest on (data replaced)";
};
};
Remove old data - appears to have no effect on problem:
async function removeCollectionFromBacktest(exchange_id, datainterval) {
const collectionToRemove = data_collections[exchange_id + datainterval + "_Backtest"]
const removeRecordsPresent = await collectionToRemove.rawCollection().count();
if (!removeRecordsPresent > 0) { return "no records" } else {
const removeComplete = await collectionToRemove.rawCollection().drop();
if (removeComplete) {
console.log("Backtest remove: Collection " + exchange_id + datainterval + " || " + removeRecordsPresent + " records removed")
return true;
};
};
};
Copy function:
async function copyCollectionForBacktest(exchange_id, datainterval, collectionForCopy) {
const collectionNameLower = (exchange_id + datainterval).toLowerCase();
const raw = collectionForCopy.rawCollection();
const aggregate = Meteor.wrapAsync(raw.aggregate, raw);
const query = [{ $match: {} }, { $out: collectionNameLower + "_backtest" }];
const backtestcollection = aggregate(query, { "allowDiskUse": true });
const copyComplete = await backtestcollection.toArray();
if (copyComplete) {
try {
delete copyComplete;
const collectionToCount = data_collections[exchange_id + datainterval + "_Backtest"]
const countToReturn = await collectionToCount.rawCollection().count();
return countToReturn;
} catch (error) {
console.log(error);
return;
};
};
};