master — https://github.com/medic/medic-webapp/pull/41902.14.x — https://github.com/medic/medic-webapp/pull/41912.13.x — https://github.com/medic/medic-webapp/pull/4192~~2.12.xWebWorkerSrv is terrible for performancefunction log(...args) {
console.log(new Date(), ...args);
}
function benchmark(db, opts) {
if(!opts) opts = {};
opts.include_docs = true;
const allDocsStart = Date.now();
let allIds;
return db.allDocs(opts)
.then(res => {
log(`[worker: ${opts.worker}] DONE: allDocs`, Date.now() - allDocsStart, 'ms');
allIds = res.rows.map(r => r.id);
})
// This code was useful in demonstrating the allDocs({ keys }) bug fixed in PouchDB 6.4
// .then(() => {
// const manualStart = Date.now();
// return db
// .allDocs(opts)
// .then(res => res.rows.filter(row => allIds.includes(row.id)))
// .then(() => log(`[worker: ${opts.worker}] DONE: manual`, Date.now() - manualStart, 'ms'));
// })
.then(() => {
const filteredStart = Date.now();
opts.keys = allIds;
return db
.allDocs(opts)
.then(() => log(`[worker: ${opts.worker}] DONE: filtered`, Date.now() - filteredStart, 'ms'));
});
}
medicWorkerDb = angular.element(document.body).injector().get('DB')();
normalDb = new PouchDB(medicWorkerDb.name);
let iter = 0;
Promise.resolve()
.then(() => log(++iter, 'BENCHMARK FOR: normalDb'))
.then(() => benchmark(normalDb))
.then(() => log(iter, 'BENCHMARK FOR: medicWorkerDb'))
.then(() => benchmark(medicWorkerDb))
.then(() => log(++iter, 'BENCHMARK FOR: normalDb'))
.then(() => benchmark(normalDb))
.then(() => log(iter, 'BENCHMARK FOR: medicWorkerDb'))
.then(() => benchmark(medicWorkerDb))
.then(() => log(++iter, 'BENCHMARK FOR: normalDb'))
.then(() => benchmark(normalDb))
.then(() => log(iter, 'BENCHMARK FOR: medicWorkerDb'))
.then(() => benchmark(medicWorkerDb))
.then(() => log(++iter, 'BENCHMARK FOR: normalDb'))
.then(() => benchmark(normalDb))
.then(() => log(iter, 'BENCHMARK FOR: medicWorkerDb'))
.then(() => benchmark(medicWorkerDb))
.then(() => log(++iter, 'BENCHMARK FOR: normalDb'))
.then(() => benchmark(normalDb))
.then(() => log(iter, 'BENCHMARK FOR: medicWorkerDb'))
.then(() => benchmark(medicWorkerDb))
.catch(log);
worker-pouch is mildly helpful for performanceuser = ?;
localDbName = ?; // re-use this to prevent re-replication every iteration
db = new PouchDB(localDbName);
function benchmark(db, opts) {
if(!opts) opts = {};
opts.include_docs = true;
const allDocsStart = Date.now();
let allIds;
return db.allDocs(opts)
.then(res => {
console.log(`[worker: ${opts.worker}] DONE: allDocs`, Date.now() - allDocsStart, 'ms');
allIds = res.rows.map(r => r.id);
})
.then(() => {
const manualStart = Date.now();
return db
.allDocs(opts)
.then(res => res.rows.filter(row => allIds.includes(row.id)))
.then(() => console.log(`[worker: ${opts.worker}] DONE: manual`, Date.now() - manualStart, 'ms'));
})
.then(() => {
const filteredStart = Date.now();
opts.keys = allIds;
return db
.allDocs(opts)
.then(() => console.log(`[worker: ${opts.worker}] DONE: filtered`, Date.now() - filteredStart, 'ms'));
});
}
let iter = 0;
db.replicate.from(`http://${user}:pass@localhost:5988/medic`, {
doc_ids: [`org.couchdb.user:${user}`],
timeout: 1000*60*10,
})
.then(() => console.log('db replication complete.'))
.then(() => console.log(++iter, 'MAIN THREAD:'))
.then(() => benchmark(db))
.then(() => console.log(iter, 'WORKER THREAD:'))
.then(() => benchmark(db, { worker:'worker' }))
.then(() => console.log(++iter, 'MAIN THREAD:'))
.then(() => benchmark(db))
.then(() => console.log(iter, 'WORKER THREAD:'))
.then(() => benchmark(db, { worker:'worker' }))
.then(() => console.log(++iter, 'MAIN THREAD:'))
.then(() => benchmark(db))
.then(() => console.log(iter, 'WORKER THREAD:'))
.then(() => benchmark(db, { worker:'worker' }))
.then(() => console.log(++iter, 'MAIN THREAD:'))
.then(() => benchmark(db))
.then(() => console.log(iter, 'WORKER THREAD:'))
.then(() => benchmark(db, { worker:'worker' }))
.then(() => console.log(++iter, 'MAIN THREAD:'))
.then(() => benchmark(db))
.then(() => console.log(iter, 'WORKER THREAD:'))
.then(() => benchmark(db, { worker:'worker' }))
.catch(console.log);
Our WebWorker wrapper is having a terrible effect on PouchDB's performance.
I suspect the scientific approach will lead us here anyway.
static/js/services/web-worker.js to return an unadulterated WebWorker instance in browsers which support itI'm pretty sure our wrapper is only necessary for really old versions of Chrome (including Chrome 30) which didn't support logging from within a WebWorker and once we bump our support we can drop the wrapper altogether.
worker-pouch is mildly helpful for performance
NB: the real benefit to worker-pouch is multithreading so the rest of the app can keep processing rules, responding to user actions, etc while pouch does its thing. This aspect isn't captured by your testing setup.
modify static/js/services/web-worker.js to return an unadulterated WebWorker instance in browsers which support it
I like this solution. That way we give people the option to use a crosswalk version of the android app to get the performance improvement. Then we can remove the adulterated webworker altogether when we bump browser requirements in 3.0.
Running the benchmark code as above:
allDocs({ keys: all_db_ids }): 100 seconds
allDocs({ keys: all_db_ids }): does not complete
Running the benchmark code, but with the worker-pouch version first:
allDocs({ keys: all_db_ids }): app crashes
didn't get this far
modify
static/js/services/web-worker.jsto return an unadulterated WebWorker instance in browsers which support it
Actually I'd say this is already happening - polyfilling global.console inside the worker is done sensibly - only if required, and only missing methods are stubbed.
6.1.2
--> _CRASH_
With only normal DB:

With PouchDB 6.1.2, WebWorkerService should not be used. If planning to use worker-pouch, then the JS should probably be loaded directly from a file URL rather than a blob (this currently seems to be the major difference between _our_ worker-couch usage, and that at https://medic.github.io/atp/pouchdb-6.4.2/).
6.4.3Results for this version of Pouch seem consistent with for 6.1.2:

My conclusion is that we should stop using a WebWorker for PouchDB because the benefits are intangible, and the performance overhead is unbearable.
Pull requests:
master — https://github.com/medic/medic-webapp/pull/41902.14.x — https://github.com/medic/medic-webapp/pull/41912.13.x2.12.xOn Chrome desktop, results with the WebWorker are much worse, but inconsistently so:

Perhaps the worker is given a lower priority than the main JS thread.
master/2.15.x/6.4.3/WebWorker)
...finally medic-android crashed.
no-web-worker/2.15.x/6.4.3/PouchDB on main thread)(n.b. log output readsmedicWorkerDb when it really means the db returned from the Angular DB service)

Merged and backported to 2.14.x. When acceptance testing make sure performance is acceptable on Y4s (or similar) with restricted users with access to tens of thousands of docs.
Do we have a test instance with tens of thousands of docs.?
No, but that would be _very_ useful!
I've got an idea on how to test. Will work on it on Monday. In the meantime, I had some performance concerns initially but I think my Y4 was just having a slow day earlier this week and it now seems pretty much the same as before. I'll have to test on a user with a lot more data to confirm.
I've successfully tested on Y4. I upgraded a clone of the MoH Siaya instance and was able to load all of the docs on my Tecno (it took a long time to load initially but it made it). Once the app opened, warming up for the first time took a while too, but after warming up, everything was working at an acceptable pace. I then hard-closed and re-opened. It took about 8.5 minutes to re-open the app and less than 30 seconds to load any of the pages for the first time. I consider this acceptable performance for now and am moving this to ready.
Most helpful comment
I've got an idea on how to test. Will work on it on Monday. In the meantime, I had some performance concerns initially but I think my Y4 was just having a slow day earlier this week and it now seems pretty much the same as before. I'll have to test on a user with a lot more data to confirm.