@toa.io/atomicity 1.0.0-alpha.301 → 1.0.0-alpha.303
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/package.json +4 -4
- package/src/atom.js +21 -1
- package/src/measurements.js +30 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.0.0-alpha.303](https://github.com/toa-io/toa/compare/v1.0.0-alpha.302...v1.0.0-alpha.303) (2026-09-12)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **metrics:** count what no span reaches ([efabf89](https://github.com/toa-io/toa/commit/efabf89e78f98a604bb939f476a937fc9ee106b3))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# [1.0.0-alpha.302](https://github.com/toa-io/toa/compare/v1.0.0-alpha.301...v1.0.0-alpha.302) (2026-09-11)
|
|
14
|
+
|
|
15
|
+
**Note:** Version bump only for package @toa.io/atomicity
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
# [1.0.0-alpha.301](https://github.com/toa-io/toa/compare/v1.0.0-alpha.300...v1.0.0-alpha.301) (2026-09-11)
|
|
7
22
|
|
|
8
23
|
**Note:** Version bump only for package @toa.io/atomicity
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/atomicity",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.303",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Toa Atomicity Connector",
|
|
6
6
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@sesamecare-oss/redlock": "1.4.0",
|
|
21
|
-
"@toa.io/core": "1.0.0-alpha.
|
|
21
|
+
"@toa.io/core": "1.0.0-alpha.303",
|
|
22
22
|
"@toa.io/generic": "1.0.0-alpha.301",
|
|
23
23
|
"ioredis": "6.0.0",
|
|
24
24
|
"n-and-i": "0.3.4",
|
|
25
|
-
"openspan": "1.0.0-alpha.
|
|
25
|
+
"openspan": "1.0.0-alpha.303"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "b8e9dd89f6d49756944687a95dfc786f12947286"
|
|
31
31
|
}
|
package/src/atom.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { console } from 'openspan'
|
|
2
2
|
import { Connector } from '@toa.io/core'
|
|
3
3
|
import { environment } from '@toa.io/generic'
|
|
4
|
+
import { holding, waited } from './measurements.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* What one group of replicas decides together, in one place: which of them owns what, what they
|
|
@@ -119,7 +120,26 @@ export class Atom extends Connector {
|
|
|
119
120
|
if (redlock === undefined)
|
|
120
121
|
throw new Error('Locking requires atomicity. Set TOA_ATOMICITY_REDIS.')
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
const started = performance.now()
|
|
124
|
+
let acquired = false
|
|
125
|
+
|
|
126
|
+
return redlock
|
|
127
|
+
.using(this.#keys(LOCK, keys), LEASE, async (signal) => {
|
|
128
|
+
// the wait is over once the routine is entered, and what follows it is the work
|
|
129
|
+
acquired = true
|
|
130
|
+
waited(this.#name, (performance.now() - started) / 1000)
|
|
131
|
+
holding(this.#name, 1)
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
return await routine(signal)
|
|
135
|
+
} finally {
|
|
136
|
+
holding(this.#name, -1)
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.finally(() => {
|
|
140
|
+
// a lock never acquired waited for however long it was refused
|
|
141
|
+
if (!acquired) waited(this.#name, (performance.now() - started) / 1000)
|
|
142
|
+
})
|
|
123
143
|
}
|
|
124
144
|
|
|
125
145
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { registry } from 'openspan'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What locking measures.
|
|
5
|
+
*
|
|
6
|
+
* `lock()` waits for as long as it takes to acquire its keys, and that wait is inside the
|
|
7
|
+
* operation that asked for it — so a replica starving on a lock another replica will not release
|
|
8
|
+
* looks exactly like a busy component. The distribution is the signal, because a mean over waits
|
|
9
|
+
* that are usually zero says nothing.
|
|
10
|
+
*/
|
|
11
|
+
const meters = registry()
|
|
12
|
+
|
|
13
|
+
/** From a lock taken at once to one waited out for a minute. */
|
|
14
|
+
const WAITS = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 15, 60]
|
|
15
|
+
|
|
16
|
+
const wait = meters.histogram(
|
|
17
|
+
'toa.atomicity.lock.wait',
|
|
18
|
+
{ buckets: WAITS, unit: 's' },
|
|
19
|
+
{ group: null }
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const held = meters.gauge('toa.atomicity.locks', { group: null })
|
|
23
|
+
|
|
24
|
+
export function waited(group, seconds) {
|
|
25
|
+
wait.record(seconds, { group })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function holding(group, delta) {
|
|
29
|
+
held.add(delta, { group })
|
|
30
|
+
}
|