Skip to content

Commit 9676f85

Browse files
authored
WIP: Prepare to release 1.0.0-beta.1 of the addons. (dexie#425)
* Prepare to release 1.0.0-beta.1 of the addons. * Heartbeat activated in dexie-observable. Needed to keep alive during long-running sync transactions. * Fixing typo in Dexie.Observable.d.ts. * Decreasing poll timeout for workers. Also making sure heartbeat() works the same way as poll() when error occur during sync. * New karma configuration structure * CI for addons: unit tests and integration tests. Run in parallell with dexie unit tests to speed-up.
1 parent 63c4d5b commit 9676f85

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+816
-1089
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dist/*.gz
1010
# Other ignores
1111
tmp/
1212
.idea/
13+
.eslintcache
1314

1415
## Ignore Visual Studio temporary files, build results, and
1516
## files generated by popular Visual Studio add-ons.

.travis.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ matrix:
88
before_script:
99
- export DISPLAY=:99.0
1010
- sh -e /etc/init.d/xvfb start
11+
env:
12+
- TF=test
13+
- TF=addons/Dexie.Observable/test/unit
14+
- TF=addons/Dexie.Observable/test/integration
15+
- TF=addons/Dexie.Syncable/test/unit
16+
- TF=addons/Dexie.Syncable/test/integration
1117
script:
1218
- npm run build
13-
- npm run test:typings
14-
- node_modules/.bin/karma start test/karma.travis.conf.js --single-run
19+
- cd $TF
20+
- pwd
21+
- bash ./travis.sh

addons/Dexie.Observable/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
Observe changes to database - even when they happen in another browser window.
44

5-
**NOTE: This addon is still in alpha development**
6-
75
### Install
86
```
97
npm install dexie --save

addons/Dexie.Observable/bower.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
{
22
"name": "dexie-observable",
3-
"version": "0.1.9",
3+
"version": "1.0.0-beta.1",
44
"homepage": "https://dexie.org",
55
"authors": [
66
"David Fahlander"
77
],
88
"description": "Addon to Dexie that makes it possible to observe database changes no matter if they occur on other db instance or other window.",
99
"main": "dist/dexie-observable.js",
1010
"files": [
11+
"api.d.ts",
12+
"dist/dexie-observable.d.ts",
1113
"dist/dexie-observable.js",
1214
"dist/dexie-observable.js.map",
1315
"dist/dexie-observable.min.js",

addons/Dexie.Observable/package.json

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dexie-observable",
3-
"version": "0.9.3",
3+
"version": "1.0.0-beta.1",
44
"description": "Addon to Dexie that makes it possible to observe database changes no matter if they occur on other db instance or other window.",
55
"main": "dist/dexie-observable.js",
66
"module": "src/Dexie.Observable.js",
@@ -35,14 +35,12 @@
3535
"scripts": {
3636
"build": "just-build",
3737
"watch": "just-build --watch",
38-
"test": "npm run build && npm run test:typings && npm run test:local && npm run test:unit",
39-
"eslint": "eslint src",
40-
"eslint:test": "eslint test/unit --ignore-pattern bundle.js --ignore-pattern karma-env.js",
38+
"test": "npm run build && npm run test:typings && npm run test:unit && npm run test:integration",
4139
"test:unit": "karma start test/unit/karma.conf.js --single-run",
42-
"test:local": "karma start test/karma.conf.js --single-run",
43-
"test:release": "npm run test:typings && karma start test/karma.release.conf.js --single-run",
44-
"test:debug": "karma start test/karma.conf.js --log-level debug",
45-
"test:typings": "tsc -p test/test-typings/"
40+
"test:integration": "karma start test/integration/karma.conf.js --single-run",
41+
"test:typings": "tsc -p test/test-typings/",
42+
"test:unit:debug": "karma start test/unit/karma.conf.js --log-level debug",
43+
"test:integration:debug": "karma start test/integrations/karma.conf.js --log-level debug"
4644
},
4745
"just-build": {
4846
"default": [
@@ -57,7 +55,7 @@
5755
"rollup -c tools/build-configs/rollup.config.js",
5856
"node tools/replaceVersionAndDate.js dist/dexie-observable.js",
5957
"# eslint ",
60-
"eslint src"
58+
"eslint src --cache"
6159
],
6260
"release": [
6361
"just-build dexie-observable",
@@ -68,9 +66,10 @@
6866
"uglifyjs dist/dexie-observable.js -m -c -o dist/dexie-observable.min.js --source-map dist/dexie-observable.min.js.map --in-source-map dist/dexie-observable.js.map"
6967
],
7068
"test": [
71-
"# Build the test suite (for now only test/unit. test should also be ES6-ified and built. They should merge)",
69+
"# Build the unit tests (integration tests need no build)",
7270
"tsc --allowJs --moduleResolution node --lib es2015,dom -t es5 -m es2015 --outDir test/tmp/es5 --rootDir ../.. --sourceMap test/unit/unit-tests-all.js [--watch 'Compilation complete.']",
73-
"rollup -c tools/build-configs/rollup.tests.config.js"
71+
"rollup -c tools/build-configs/rollup.tests.config.js",
72+
"eslint test/unit --cache --ignore-pattern bundle.js"
7473
]
7574
},
7675
"homepage": "http://dexie.org",
@@ -82,7 +81,14 @@
8281
},
8382
"devDependencies": {
8483
"eslint": "^3.14.0",
85-
"just-build": "^0.9.12",
84+
"just-build": "^0.9.13",
85+
"karma": "^1.4.0",
86+
"karma-browserstack-launcher": "^1.1.1",
87+
"karma-chrome-launcher": "^2.0.0",
88+
"karma-firefox-launcher": "^1.0.0",
89+
"karma-mocha-reporter": "^2.2.0",
90+
"karma-qunit": "^1.2.1",
91+
"qunitjs": "^1.23.1",
8692
"rollup": "^0.41.4",
8793
"rollup-plugin-sourcemaps": "^0.4.1",
8894
"typescript": "^2.1.5",

addons/Dexie.Observable/src/Dexie.Observable.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ declare module 'dexie' {
1515
// (makes it valid to do new db.observable.SyncNode())
1616
observable: {
1717
SyncNode: Dexie.Observable.SyncNodeConstructor;
18-
Foo: Dexie.Observable.MessageEvent;
1918
sendMessage(
2019
type: string, // Don't use 'response' as it is used internally by the framework
2120
message: any, // anything that can be saved by IndexedDB

addons/Dexie.Observable/src/Dexie.Observable.js

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ export default function Observable(db) {
6565
HIBERNATE_GRACE_PERIOD = 20000, // 20 seconds
6666
// LOCAL_POLL: The time to wait before polling local db for changes and cleaning up old nodes.
6767
// Polling for changes is a fallback only needed in certain circomstances (when the onstorage event doesnt reach all listeners - when different browser windows doesnt share the same process)
68-
LOCAL_POLL = 2000; // 1 second. In real-world there will be this value + the time it takes to poll().
69-
//HEARTBEAT_INTERVAL = NODE_TIMEOUT - 5000;
68+
LOCAL_POLL = 500, // 500 ms. In real-world there will be this value + the time it takes to poll(). A small value is needed in Workers where we cannot rely on storage event.
69+
HEARTBEAT_INTERVAL = NODE_TIMEOUT - 5000;
7070

7171
var localStorage = Observable.localStorageImpl;
7272

@@ -118,7 +118,8 @@ export default function Observable(db) {
118118
get: function() { return mySyncNode.node; }
119119
});
120120

121-
var pollHandle = null;
121+
var pollHandle = null,
122+
heartbeatHandle = null;
122123

123124
if (Dexie.fake) {
124125
// This code will never run.
@@ -194,6 +195,8 @@ export default function Observable(db) {
194195

195196
if (pollHandle) clearTimeout(pollHandle);
196197
pollHandle = null;
198+
if (heartbeatHandle) clearTimeout(heartbeatHandle);
199+
heartbeatHandle = null;
197200
return origClose.apply(this, arguments);
198201
};
199202
});
@@ -256,6 +259,8 @@ export default function Observable(db) {
256259
Observable.on('intercomm', onIntercomm);
257260
// Start polling for changes and do cleanups:
258261
pollHandle = setTimeout(poll, LOCAL_POLL);
262+
// Start heartbeat
263+
heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL);
259264
});
260265
});
261266
}).then(function () {
@@ -348,11 +353,24 @@ export default function Observable(db) {
348353
return promise;
349354
}
350355

351-
/*function heartbeat() {
352-
var ourSyncNodeId = mySyncNode.node && mySyncNode.node.id;
353-
if (!ourSyncNodeId) return;
356+
/**
357+
* The reason we need heartbeat in parallell with poll() is due to the risk of long-running
358+
* transactions while syncing changes from server to client in Dexie.Syncable. That transaction will
359+
* include _changes (which will block readChanges()) but not _syncNodes. So this heartbeat will go on
360+
* during that changes are being applied and update our lastHeartBeat property while poll() is waiting.
361+
* When cleanup() (who also is blocked by the sync) wakes up, it won't kill the master node because this
362+
* heartbeat job will have updated the master node's heartbeat during the long-running sync transaction.
363+
*
364+
* If we did not have this heartbeat, and a server send lots of changes that took more than NODE_TIMEOUT
365+
* (20 seconds), another node waking up after the sync would kill the master node and take over because
366+
* it would believe it was dead.
367+
*/
368+
function heartbeat() {
369+
heartbeatHandle = null;
370+
var currentInstance = mySyncNode.node && mySyncNode.node.id;
371+
if (!currentInstance) return;
354372
db.transaction('rw!', db._syncNodes, ()=>{
355-
db._syncNodes.where({id: ourSyncNodeId}).first(ourSyncNode => {
373+
db._syncNodes.where({id: currentInstance}).first(ourSyncNode => {
356374
if (!ourSyncNode) {
357375
// We do not exist anymore. Call db.close() to teardown polls etc.
358376
if (db.isOpen()) db.close();
@@ -362,10 +380,14 @@ export default function Observable(db) {
362380
ourSyncNode.deleteTimeStamp = null; // Reset "deleteTimeStamp" flag if it was there.
363381
return db._syncNodes.put(ourSyncNode);
364382
});
365-
}).then(()=>{
366-
setTimeout(heartbeat, HEARTBEAT_INTERVAL);
383+
}).catch('DatabaseClosedError', () => {
384+
// Ignore silently
385+
}).finally(() => {
386+
if (mySyncNode.node && mySyncNode.node.id === currentInstance && db.isOpen()) {
387+
heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL);
388+
}
367389
});
368-
}*/
390+
}
369391

370392
function poll() {
371393
pollHandle = null;
@@ -381,7 +403,7 @@ export default function Observable(db) {
381403
})
382404
.finally(function() {
383405
// Poll again in given interval:
384-
if (mySyncNode.node && mySyncNode.node.id === currentInstance) {
406+
if (mySyncNode.node && mySyncNode.node.id === currentInstance && db.isOpen()) {
385407
pollHandle = setTimeout(poll, LOCAL_POLL);
386408
}
387409
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// workerImports will be used by tests-open.js in the dexie test suite when
2+
// launching a Worker. This line will instruct the worker to import dexie-observable.
3+
window.workerImports.push("../addons/Dexie.Observable/dist/dexie-observable.js");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Include common configuration
2+
const {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/karma.common');
3+
4+
module.exports = function (config) {
5+
const browserMatrixOverrides = {
6+
// Be fine with testing on local travis firefox for both pull requests and pushs.
7+
ci: ["Firefox"],
8+
// IE indexedDB hangs sporadically. Avoid it on integration tests to prohibit the
9+
// likeliness of having to restart the travis builds over and over. We're testing
10+
// it on the dexie main suite. That's enough.
11+
full: defaultBrowserMatrix.full.filter(b => !/bs_ie/i.test(b))
12+
};
13+
14+
const cfg = getKarmaConfig(browserMatrixOverrides, {
15+
// Base path should point at the root
16+
basePath: '../../../../',
17+
// Use alternate port than the unit test uses, so they can run in parallel on a dev machine.
18+
port: karmaCommon.port + 1,
19+
// The files needed to apply dexie-observable to the standard dexie unit tests.
20+
files: karmaCommon.files.concat([
21+
'dist/dexie.js',
22+
'addons/Dexie.Observable/test/integration/karma-env.js',
23+
'addons/Dexie.Observable/dist/dexie-observable.js', // Apply observable addon
24+
'test/bundle.js', // The dexie standard test suite
25+
{ pattern: 'addons/Dexie.Observable/dist/*.map', watched: false, included: false }
26+
])
27+
});
28+
29+
config.set(cfg);
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Dexie Unit tests with Dexie.Observable applied</title>
6+
<base href="../../../../test/" />
7+
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
8+
</head>
9+
<body>
10+
<div id="qunit"></div>
11+
<div id="qunit-fixture"></div>
12+
<script src="babel-polyfill/polyfill.min.js"></script>
13+
<script>
14+
// Hack for making the WebWorker test behave also here...
15+
window.workerSource = "worker.js";
16+
window.workerImports = ["../dist/dexie.js", "../addons/Dexie.Observable/dist/dexie-observable.js"];
17+
</script>
18+
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
19+
<script src="../dist/dexie.js"></script>
20+
<script src="../addons/Dexie.Observable/dist/dexie-observable.js"></script>
21+
<script src="bundle.js"></script>
22+
</body>
23+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash -e
2+
echo "Installing dependencies for dexie-observable"
3+
npm install >/dev/null
4+
npm run build
5+
npm run test:integration

addons/Dexie.Observable/test/karma-env.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

addons/Dexie.Observable/test/karma.conf.js

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)