fix(core): update

This commit is contained in:
Philipp Kunz 2023-08-15 01:01:16 +02:00
parent 0e55cd8876
commit 2ff3a4e0b7
8 changed files with 186 additions and 116 deletions

View File

@ -22,16 +22,16 @@
},
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
"dependencies": {
"@push.rocks/lik": "^6.0.2",
"@push.rocks/lik": "^6.0.5",
"@push.rocks/smartdelay": "^3.0.1",
"@push.rocks/smartlog": "^3.0.2",
"@push.rocks/smartmongo": "^2.0.10",
"@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/smartrx": "^3.0.6",
"@push.rocks/smartstring": "^4.0.7",
"@push.rocks/smarttime": "^4.0.1",
"@push.rocks/smarttime": "^4.0.5",
"@push.rocks/smartunique": "^3.0.3",
"@push.rocks/taskbuffer": "^3.1.2",
"@push.rocks/taskbuffer": "^3.1.3",
"@tsclass/tsclass": "^4.0.42",
"mongodb": "^5.7.0"
},
@ -41,7 +41,7 @@
"@gitzone/tstest": "^1.0.77",
"@push.rocks/qenv": "^6.0.2",
"@push.rocks/tapbundle": "^5.0.15",
"@types/node": "^20.4.10",
"@types/node": "^20.5.0",
"@types/shortid": "0.0.29"
},
"files": [

118
pnpm-lock.yaml generated
View File

@ -6,8 +6,8 @@ settings:
dependencies:
'@push.rocks/lik':
specifier: ^6.0.2
version: 6.0.3
specifier: ^6.0.5
version: 6.0.5
'@push.rocks/smartdelay':
specifier: ^3.0.1
version: 3.0.5
@ -27,14 +27,14 @@ dependencies:
specifier: ^4.0.7
version: 4.0.7
'@push.rocks/smarttime':
specifier: ^4.0.1
version: 4.0.4
specifier: ^4.0.5
version: 4.0.5
'@push.rocks/smartunique':
specifier: ^3.0.3
version: 3.0.3
'@push.rocks/taskbuffer':
specifier: ^3.1.2
version: 3.1.2
specifier: ^3.1.3
version: 3.1.3
'@tsclass/tsclass':
specifier: ^4.0.42
version: 4.0.42
@ -48,10 +48,10 @@ devDependencies:
version: 2.1.66
'@gitzone/tsrun':
specifier: ^1.2.44
version: 1.2.44(@types/node@20.4.10)
version: 1.2.44(@types/node@20.5.0)
'@gitzone/tstest':
specifier: ^1.0.77
version: 1.0.77(@types/node@20.4.10)(sinon@15.2.0)
version: 1.0.77(@types/node@20.5.0)(sinon@15.2.0)
'@push.rocks/qenv':
specifier: ^6.0.2
version: 6.0.2
@ -59,8 +59,8 @@ devDependencies:
specifier: ^5.0.15
version: 5.0.15(sinon@15.2.0)
'@types/node':
specifier: ^20.4.10
version: 20.4.10
specifier: ^20.5.0
version: 20.5.0
'@types/shortid':
specifier: 0.0.29
version: 0.0.29
@ -87,7 +87,7 @@ packages:
dependencies:
'@api.global/typedrequest-interfaces': 3.0.1
'@push.rocks/isounique': 1.0.5
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartpromise': 4.0.3
'@push.rocks/webrequest': 3.0.32
@ -929,13 +929,13 @@ packages:
- supports-color
dev: true
/@gitzone/tsrun@1.2.44(@types/node@20.4.10):
/@gitzone/tsrun@1.2.44(@types/node@20.5.0):
resolution: {integrity: sha512-7AfL9u+TmD7gLiRaTCimhWm5rq9GGBQnOF4q1FnFh2CAb1FbK5fzUVbj6wo3zGS2H+MSm6dqFA6mvdBI1ox0mQ==}
hasBin: true
dependencies:
'@push.rocks/smartfile': 10.0.28
'@push.rocks/smartshell': 3.0.3
ts-node: 10.9.1(@types/node@20.4.10)(typescript@5.1.6)
ts-node: 10.9.1(@types/node@20.5.0)(typescript@5.1.6)
typescript: 5.1.6
transitivePeerDependencies:
- '@swc/core'
@ -944,13 +944,13 @@ packages:
- supports-color
dev: true
/@gitzone/tstest@1.0.77(@types/node@20.4.10)(sinon@15.2.0):
/@gitzone/tstest@1.0.77(@types/node@20.5.0)(sinon@15.2.0):
resolution: {integrity: sha512-YzBXnNqkYOiFf8xAA+m8owblrmAut8ukINghYy4DXoUR+5g1IKrpTjK4A8HzIsvVsQRyHPsQ2YFtsk+utqdivQ==}
hasBin: true
dependencies:
'@apiglobal/typedserver': 2.0.65
'@gitzone/tsbundle': 2.0.8
'@gitzone/tsrun': 1.2.44(@types/node@20.4.10)
'@gitzone/tsrun': 1.2.44(@types/node@20.5.0)
'@push.rocks/consolecolor': 2.0.1
'@push.rocks/smartbrowser': 2.0.5
'@push.rocks/smartdelay': 3.0.5
@ -1113,14 +1113,14 @@ packages:
/@push.rocks/isounique@1.0.5:
resolution: {integrity: sha512-Z0BVqZZOCif1THTbIKWMgg0wxCzt9CyBtBBqQJiZ+jJ0KlQFrQHNHrPt81/LXe/L4x0cxWsn0bpL6W5DNSvNLw==}
/@push.rocks/lik@6.0.3:
resolution: {integrity: sha512-YPA2PfubtD6YSWo5AXx8J10ZbEMkGezrBw93+2jq7ASSNnmGnXYMNuCOnfj+ZLqT7mT0cQOaUxmfyBKF1gG+ng==}
/@push.rocks/lik@6.0.5:
resolution: {integrity: sha512-rDSPVknpJDcY3yx4w3lNQfpRkBRuxYVIJKrkiODdH27X0z3+XU4e/iAWKySuLq6H7dAoxSHJDf6BrCO+3Y8kcw==}
dependencies:
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartmatch': 2.0.0
'@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartrx': 3.0.6
'@push.rocks/smarttime': 4.0.4
'@push.rocks/smarttime': 4.0.5
'@types/minimatch': 5.1.2
'@types/symbol-tree': 3.2.2
symbol-tree: 3.2.4
@ -1170,16 +1170,16 @@ packages:
/@push.rocks/smartdata@5.0.23:
resolution: {integrity: sha512-t2bHJpULbckTQZhBpWQ9OWvq0iTwklHIKs66CrgNQATFHvjTQnxrCBLY+NC+gE+53OOC6qv5Z52SAoTGlirxuQ==}
dependencies:
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartlog': 3.0.3
'@push.rocks/smartmongo': 2.0.10
'@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartrx': 3.0.6
'@push.rocks/smartstring': 4.0.7
'@push.rocks/smarttime': 4.0.4
'@push.rocks/smarttime': 4.0.5
'@push.rocks/smartunique': 3.0.3
'@push.rocks/taskbuffer': 3.1.2
'@push.rocks/taskbuffer': 3.1.3
'@tsclass/tsclass': 4.0.42
mongodb: 5.7.0
transitivePeerDependencies:
@ -1218,7 +1218,7 @@ packages:
/@push.rocks/smartfile@10.0.28:
resolution: {integrity: sha512-Bza5xwJuXGeIokr9xeLx1LSGuXvIYLtJimz0X6lB2Sv2kurlIjpb+/ix4KqsG9eBhvzo6ncqqjgnLAUyUQQjfw==}
dependencies:
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartfile-interfaces': 1.0.7
'@push.rocks/smarthash': 3.0.2
@ -1358,10 +1358,10 @@ packages:
url: 0.11.1
dev: false
/@push.rocks/smarttime@4.0.4:
resolution: {integrity: sha512-PTYxvl6Rr5eSOKPbB0S5+ym6z6zfI/e1wqmVxX8QjnZ5ZIvhGfAoCZ7sie+Zd4OJ4nCG8UClgk5LrFaN3zUnZA==}
/@push.rocks/smarttime@4.0.5:
resolution: {integrity: sha512-vf0Jh+jnMt59l4zbmxdkoPdIMhtO5ghFQn8wn9hX+oOtog56ddrwvdubs9CtDNCPoA8YEKL8Izp1uY21NIgrmA==}
dependencies:
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartpromise': 4.0.3
croner: 5.7.0
@ -1390,7 +1390,7 @@ packages:
'@push.rocks/smartenv': 5.0.5
'@push.rocks/smartexpect': 1.0.21
'@push.rocks/smartpromise': 4.0.3
'@push.rocks/smarttime': 4.0.4
'@push.rocks/smarttime': 4.0.5
transitivePeerDependencies:
- bufferutil
- sinon
@ -1398,16 +1398,16 @@ packages:
- utf-8-validate
dev: true
/@push.rocks/taskbuffer@3.1.2:
resolution: {integrity: sha512-hPhxYaPTu+UyGB8xboPC7cHcEtzAO0Co57Zw2T/bDtTeijCgKV6WtGvYXQjwA2JBT9KVjkQXRWRonskN70G5Mg==}
/@push.rocks/taskbuffer@3.1.3:
resolution: {integrity: sha512-f5v02i/sb47dZkCmC+tnrwhvPLKtJpDQsg/gc3IqWu4Ufy7+X2y4TT85z43/qDIMb/Afm5ljUEavlsTXi1ctWQ==}
dependencies:
'@push.rocks/isounique': 1.0.5
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartlog': 3.0.3
'@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartrx': 3.0.6
'@push.rocks/smarttime': 4.0.4
'@push.rocks/smarttime': 4.0.5
dev: false
/@push.rocks/webrequest@3.0.32:
@ -1429,7 +1429,7 @@ packages:
resolution: {integrity: sha512-B/a/M+udyr0pByGdOEcWyY+gugIx36YJXWwNUrslh9XjIWs+0NKSFJRnZKuVYSCHOnc/WblAOceSlGVwFmYVBw==}
dependencies:
'@apiglobal/typedrequest-interfaces': 2.0.1
'@push.rocks/lik': 6.0.3
'@push.rocks/lik': 6.0.5
'@push.rocks/smartenv': 5.0.5
'@push.rocks/smartjson': 5.0.6
'@push.rocks/smartpromise': 4.0.3
@ -2572,7 +2572,7 @@ packages:
/@types/accepts@1.3.5:
resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/babel__code-frame@7.0.3:
@ -2583,7 +2583,7 @@ packages:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.35
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/buffer-json@2.0.1:
@ -2609,14 +2609,14 @@ packages:
/@types/clean-css@4.2.6:
resolution: {integrity: sha512-Ze1tf+LnGPmG6hBFMi0B4TEB0mhF7EiMM5oyjLDNPE9hxrPU0W+5+bHvO+eFPA+bt0iC1zkQMoU/iGdRVjcRbw==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
source-map: 0.6.1
dev: true
/@types/co-body@6.1.0:
resolution: {integrity: sha512-3e0q2jyDAnx/DSZi0z2H0yoZ2wt5yRDZ+P7ymcMObvq0ufWRT4tsajyO+Q1VwVWiv9PRR4W3YEjEzBjeZlhF+w==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
'@types/qs': 6.9.7
dev: true
@ -2629,7 +2629,7 @@ packages:
/@types/connect@3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/content-disposition@0.5.5:
@ -2650,13 +2650,13 @@ packages:
'@types/connect': 3.4.35
'@types/express': 4.17.17
'@types/keygrip': 1.0.2
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/cors@2.8.13:
resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/debounce@1.2.1:
@ -2670,7 +2670,7 @@ packages:
/@types/express-serve-static-core@4.17.35:
resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
'@types/send': 0.17.1
@ -2695,40 +2695,40 @@ packages:
/@types/finalhandler@1.2.0:
resolution: {integrity: sha512-NgEZKOhxUSXkwNnWNaMXZaopQ5aFGPAYiEpEWIkQ6Dzc4iS0M1oQsvWne2t+ex9QZUAdTz/ZT4tOXJhWtP6mCw==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/from2@2.3.2:
resolution: {integrity: sha512-s1pdctxW2+CA4FOxxTBRxC3RKQL9Br1a2s2LngP4jh1BI84JBL3mDXj87EwcckN9z/IXp8o3ySmvZveGEAAwqw==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/fs-extra@11.0.1:
resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
dependencies:
'@types/jsonfile': 6.1.1
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/fs-extra@9.0.13:
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: false
/@types/glob@7.2.0:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: false
/@types/glob@8.1.0:
resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/html-minifier@4.0.2:
@ -2777,7 +2777,7 @@ packages:
/@types/jsonfile@6.1.1:
resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/keygrip@1.0.2:
@ -2800,7 +2800,7 @@ packages:
'@types/http-errors': 2.0.1
'@types/keygrip': 1.0.2
'@types/koa-compose': 3.2.5
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/mime-types@2.1.1:
@ -2824,8 +2824,8 @@ packages:
resolution: {integrity: sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==}
dev: true
/@types/node@20.4.10:
resolution: {integrity: sha512-vwzFiiy8Rn6E0MtA13/Cxxgpan/N6UeNYR9oUu6kuJWxu6zCk98trcDp8CBhbtaeuq9SykCmXkFr2lWLoPcvLg==}
/@types/node@20.5.0:
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
/@types/parse5@6.0.3:
resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
@ -2854,7 +2854,7 @@ packages:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies:
'@types/mime': 1.3.2
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/serve-static@1.15.2:
@ -2862,7 +2862,7 @@ packages:
dependencies:
'@types/http-errors': 2.0.1
'@types/mime': 3.0.1
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/shortid@0.0.29:
@ -2891,7 +2891,7 @@ packages:
/@types/through2@2.0.38:
resolution: {integrity: sha512-YFu+nHmjxMurkH1BSzA0Z1WrKDAY8jUKPZctNQn7mc+/KKtp2XxnclHFXxdB1m7Iqnzb5aywgP8TMK283LezGQ==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
/@types/trusted-types@2.0.3:
resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==}
@ -2913,7 +2913,7 @@ packages:
/@types/whatwg-url@8.2.2:
resolution: {integrity: sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
'@types/webidl-conversions': 7.0.0
dev: false
@ -2928,14 +2928,14 @@ packages:
/@types/ws@7.4.7:
resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==}
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
/@types/yauzl@2.10.0:
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
requiresBuild: true
dependencies:
'@types/node': 20.4.10
'@types/node': 20.5.0
dev: true
optional: true
@ -3876,7 +3876,7 @@ packages:
dependencies:
'@types/cookie': 0.4.1
'@types/cors': 2.8.13
'@types/node': 20.4.10
'@types/node': 20.5.0
accepts: 1.3.8
base64id: 2.0.0
cookie: 0.4.2
@ -3896,7 +3896,7 @@ packages:
dependencies:
'@types/cookie': 0.4.1
'@types/cors': 2.8.13
'@types/node': 20.4.10
'@types/node': 20.5.0
accepts: 1.3.8
base64id: 2.0.0
cookie: 0.4.2
@ -6618,7 +6618,7 @@ packages:
hasBin: true
dev: true
/ts-node@10.9.1(@types/node@20.4.10)(typescript@5.1.6):
/ts-node@10.9.1(@types/node@20.5.0)(typescript@5.1.6):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
@ -6637,7 +6637,7 @@ packages:
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
'@types/node': 20.4.10
'@types/node': 20.5.0
acorn: 8.10.0
acorn-walk: 8.2.0
arg: 4.1.3

View File

@ -27,34 +27,31 @@ tap.test('should instantiate DistributedClass', async (tools) => {
tap.test('DistributedClass should update the time', async (tools) => {
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
await distributedCoordinator.start();
console.log('test: started');
const initialTime = distributedCoordinator.ownInstance.data.lastUpdated;
await distributedCoordinator.sendHeartbeat();
console.log('test: sent heartbeat');
const updatedTime = distributedCoordinator.ownInstance.data.lastUpdated;
expect(updatedTime).toBeGreaterThan(initialTime);
await distributedCoordinator.stop();
});
tap.test('should instantiate SmartdataDistributedCoordinator', async (tools) => {
const coordinator = new SmartdataDistributedCoordinator(testDb);
await coordinator.start();
expect(coordinator).toBeInstanceOf(SmartdataDistributedCoordinator);
await coordinator.stop();
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
await distributedCoordinator.start();
expect(distributedCoordinator).toBeInstanceOf(SmartdataDistributedCoordinator);
await distributedCoordinator.stop();
});
tap.test('SmartdataDistributedCoordinator should update leader status', async (tools) => {
const coordinator = new SmartdataDistributedCoordinator(testDb);
await coordinator.start();
await coordinator.checkAndMaybeLead();
expect(coordinator.ownInstance.data.elected).toBeOneOf([true, false]);
await coordinator.stop();
process.exit(0);
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
await distributedCoordinator.start();
await distributedCoordinator.checkAndMaybeLead();
expect(distributedCoordinator.ownInstance.data.elected).toBeOneOf([true, false]);
await distributedCoordinator.stop();
});
tap.test('SmartdataDistributedCoordinator should handle distributed task requests', async (tools) => {
const coordinator = new SmartdataDistributedCoordinator(testDb);
await coordinator.start();
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
await distributedCoordinator.start();
const mockTaskRequest: taskbuffer.distributedCoordination.IDistributedTaskRequest = {
submitterId: "mockSubmitter12345", // Some unique mock submitter ID
@ -66,15 +63,15 @@ tap.test('SmartdataDistributedCoordinator should handle distributed task request
status: 'requesting'
};
const response = await coordinator.fireDistributedTaskRequest(mockTaskRequest);
expect(response).toBeTruthy(); // based on your expected structure for the response
await coordinator.stop();
const response = await distributedCoordinator.fireDistributedTaskRequest(mockTaskRequest);
console.log(response) // based on your expected structure for the response
await distributedCoordinator.stop();
});
tap.test('SmartdataDistributedCoordinator should update distributed task requests', async (tools) => {
const coordinator = new SmartdataDistributedCoordinator(testDb);
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
await coordinator.start();
await distributedCoordinator.start();
const mockTaskRequest: taskbuffer.distributedCoordination.IDistributedTaskRequest = {
submitterId: "mockSubmitter12345", // Some unique mock submitter ID
@ -87,18 +84,27 @@ tap.test('SmartdataDistributedCoordinator should update distributed task request
};
await coordinator.updateDistributedTaskRequest(mockTaskRequest);
await distributedCoordinator.updateDistributedTaskRequest(mockTaskRequest);
// Here, we can potentially check if a DB entry got updated or some other side-effect of the update method.
await distributedCoordinator.stop();
});
tap.test('should elect only one leader amongst multiple instances', async (tools) => {
const coordinators = Array.from({ length: totalInstances }).map(() => new SmartdataDistributedCoordinator(testDb));
await Promise.all(coordinators.map(coordinator => coordinator.init()));
await Promise.all(coordinators.map(coordinator => coordinator.checkAndMaybeLead()));
await Promise.all(coordinators.map(coordinator => coordinator.start()));
const leaders = coordinators.filter(coordinator => coordinator.ownInstance.data.elected);
for (const leader of leaders) {
console.log(leader.ownInstance);
}
expect(leaders.length).toEqual(1);
// stopping clears a coordinator from being elected.
await Promise.all(coordinators.map(coordinator => coordinator.stop()));
});
tap.test('should clean up', async () => {
await smartmongoInstance.stopAndDumpToDir(`.nogit/testdata/`);
setTimeout(() => process.exit(0), 1000);
})
tap.start({ throwOnError: true });

View File

@ -26,7 +26,7 @@ tap.test('should create a testinstance as database', async () => {
tap.skip.test('should connect to atlas', async (tools) => {
const databaseName = `test-smartdata-${smartunique.shortId()}`;
testDb = new smartdata.SmartdataDb({
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGO_URL'),
mongoDbName: databaseName,
});
await testDb.init();

View File

@ -28,7 +28,7 @@ tap.test('should create a testinstance as database', async () => {
tap.skip.test('should connect to atlas', async (tools) => {
const databaseName = `test-smartdata-${smartunique.shortId()}`;
testDb = new smartdata.SmartdataDb({
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGO_URL'),
mongoDbName: databaseName,
});
await testDb.init();

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartdata',
version: '5.0.26',
version: '5.0.27',
description: 'do more with data'
}

View File

@ -13,6 +13,7 @@ export class DistributedClass extends SmartDataDbDoc<DistributedClass, Distribut
public data: {
status: 'bidding' | 'settled' | 'initializing' | 'stopped';
biddingShortcode?: string;
biddingStartTime?: number;
lastUpdated: number;
elected: boolean;
/**
@ -52,11 +53,17 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
}
public async stop() {
if (this.ownInstance?.data.elected) {
this.ownInstance.data.elected = false;
} else {
console.log(`can't stop a distributed instance that has not been started yet.`);
}
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
if (this.ownInstance?.data.elected) {
this.ownInstance.data.elected = false;
}
if (this.ownInstance?.data.status === 'stopped') {
console.log(`stopping a distributed instance that has not been started yet.`);
}
this.ownInstance.data.status = 'stopped';
await this.ownInstance.save();
console.log(`stopped ${this.ownInstance.id}`);
});
}
public id = plugins.smartunique.uni('distributedInstance');
@ -64,15 +71,32 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
private startHeartbeat = async () => {
while (this.ownInstance.data.status !== 'stopped') {
await this.sendHeartbeat();
await plugins.smartdelay.delayFor(10000);
await plugins.smartdelay.delayForRandom(5000, 10000);
}
};
public async sendHeartbeat() {
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
if (this.ownInstance.data.status === 'stopped') {
console.log(`aborted sending heartbeat because status is stopped`);
return;
}
await this.ownInstance.updateFromDb();
this.ownInstance.data.lastUpdated = Date.now();
await this.ownInstance.save();
console.log(`sent heartbeat for ${this.ownInstance.id}`);
const allInstances = DistributedClass.getInstances({});
});
if (this.ownInstance.data.status === 'stopped') {
console.log(`aborted sending heartbeat because status is stopped`);
return;
}
const eligibleLeader = await this.getEligibleLeader();
// not awaiting here because we don't want to block the heartbeat
this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
if (!eligibleLeader && this.ownInstance.data.status === 'settled') {
this.checkAndMaybeLead();
}
});
}
private async init() {
@ -90,6 +114,8 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
};
await this.ownInstance.save();
});
} else {
console.warn(`distributed instance already initialized`);
}
// lets enable the heartbeat
@ -101,42 +127,73 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
return this.ownInstance;
}
public async getEligibleLeader() {
return this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
const allInstances = await DistributedClass.getInstances({});
let leaders = allInstances.filter((instanceArg) => instanceArg.data.elected === true);
const eligibleLeader = leaders.find(
(leader) =>
leader.data.lastUpdated >=
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ seconds: 20 })
);
return eligibleLeader;
});
}
// --> leader election
public async checkAndMaybeLead() {
const allInstances = await DistributedClass.getInstances({});
let leader = allInstances.find((instanceArg) => instanceArg.data.elected === true);
if (
leader &&
leader.data.lastUpdated >=
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ minutes: 1 })
) {
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
this.ownInstance.data.status = 'initializing';
this.ownInstance.save();
});
if (await this.getEligibleLeader()) {
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
await this.ownInstance.updateFromDb();
this.ownInstance.data.status = 'settled';
await this.ownInstance.save();
console.log(`${this.ownInstance.id} settled as follower`);
});
return;
} else if (
(await DistributedClass.getInstances({})).find((instanceArg) => {
instanceArg.data.status === 'bidding' &&
instanceArg.data.biddingStartTime <= Date.now() - 4000 &&
instanceArg.data.biddingStartTime >= Date.now() - 30000;
})
) {
console.log('too late to the bidding party... waiting for next round.');
return;
} else {
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
await this.ownInstance.updateFromDb();
this.ownInstance.data.status = 'bidding';
this.ownInstance.data.biddingStartTime = Date.now();
this.ownInstance.data.biddingShortcode = plugins.smartunique.shortId();
await this.ownInstance.save();
console.log('bidding code stored.');
});
await plugins.smartdelay.delayFor(plugins.smarttime.getMilliSecondsFromUnits({ minutes: 2 }));
console.log(`bidding for leadership...`);
await plugins.smartdelay.delayFor(
plugins.smarttime.getMilliSecondsFromUnits({ seconds: 20 })
);
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
let biddingInstances = await DistributedClass.getInstances({});
biddingInstances = biddingInstances.filter(
(instanceArg) =>
!instanceArg.data.elected &&
instanceArg.data.status === 'bidding' &&
instanceArg.data.lastUpdated >=
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ minutes: 1 })
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ seconds: 25 })
);
console.log(`found ${biddingInstances.length} bidding instances...`);
this.ownInstance.data.elected = true;
for (const biddingInstance of biddingInstances) {
if (biddingInstance.data.biddingShortcode < this.ownInstance.data.biddingShortcode) {
this.ownInstance.data.elected = false;
}
}
await plugins.smartdelay.delayFor(5000);
console.log(`settling with status elected = ${this.ownInstance.data.elected}`);
this.ownInstance.data.status = 'settled';
await this.ownInstance.save();
});
if (this.ownInstance.data.elected) {
@ -151,20 +208,20 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
* the leading is implemented here
*/
public async leadFunction() {
const ownInstance = await this.init();
const watcher = await DistributedClass.watch({});
/**
* this function is started once per unique job request
*/
const startResultTimer = async () => {};
watcher.changeSubject.subscribe({
next: async (distributedDoc) => {
distributedDoc;
},
});
while (this.ownInstance.data.status !== 'stopped') {
await plugins.smartdelay.delayFor(1000);
while (this.ownInstance.data.status !== 'stopped' && this.ownInstance.data.elected) {
const allInstances = await DistributedClass.getInstances({});
for (const instance of allInstances) {
if (instance.data.status === 'stopped') {
await instance.delete();
};
}
await plugins.smartdelay.delayFor(10000);
}
}
@ -172,8 +229,11 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
public async fireDistributedTaskRequest(
taskRequestArg: plugins.taskbuffer.distributedCoordination.IDistributedTaskRequest
): Promise<plugins.taskbuffer.distributedCoordination.IDistributedTaskRequestResult> {
const ownInstance = await this.init();
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
if (!this.ownInstance) {
console.error('instance need to be started first...');
return;
}
this.ownInstance.data.taskRequests.push(taskRequestArg);
await this.ownInstance.save();
});
@ -190,6 +250,10 @@ export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distribu
infoBasisItem.taskExecutionTime === infoBasisArg.taskExecutionTime
);
});
if (!existingInfoBasis) {
console.warn('trying to update a non existing task request... aborting!');
return;
}
Object.assign(existingInfoBasis, infoBasisArg);
await this.ownInstance.save();
plugins.smartdelay.delayFor(60000).then(() => {

View File

@ -257,7 +257,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
* updates an object from db
*/
public async updateFromDb() {
const mongoDbNativeDoc = await this.collection.findOne(this.createIdentifiableObject());
const mongoDbNativeDoc = await this.collection.findOne(await this.createIdentifiableObject());
for (const key of Object.keys(mongoDbNativeDoc)) {
this[key] = mongoDbNativeDoc[key];
}