ultravisor 1.0.23 → 1.0.25
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/docs/queue-followups/03-config-migration.md +123 -0
- package/docs/queue-followups/04-direct-dispatch-phase-emission.md +128 -0
- package/package.json +3 -1
- package/source/Ultravisor.cjs +4 -0
- package/source/cli/Ultravisor-CLIProgram.cjs +18 -0
- package/source/datamodel/Ultravisor-BeaconQueue.json +165 -0
- package/source/datamodel/Ultravisor-Fleet.json +66 -0
- package/source/services/Ultravisor-Beacon-ActionDefaults.cjs +174 -0
- package/source/services/Ultravisor-Beacon-Coordinator.cjs +479 -8
- package/source/services/Ultravisor-Beacon-RunManager.cjs +169 -0
- package/source/services/Ultravisor-Beacon-Scheduler.cjs +789 -0
- package/source/services/Ultravisor-DirectoryDistributor.cjs +280 -0
- package/source/services/Ultravisor-ExecutionEngine.cjs +227 -4
- package/source/services/Ultravisor-ExecutionManifest.cjs +1 -0
- package/source/services/Ultravisor-FleetManager.cjs +853 -0
- package/source/services/persistence/Ultravisor-Beacon-FleetStore.cjs +570 -0
- package/source/services/persistence/Ultravisor-Beacon-QueueStore.cjs +886 -0
- package/source/services/tasks/file-system/Ultravisor-TaskConfigs-FileSystem.cjs +81 -0
- package/source/services/tasks/file-system/definitions/chunked-write.json +38 -0
- package/source/web_server/Ultravisor-API-Server.cjs +588 -0
- package/test/Ultravisor_BeaconQueue_tests.js +502 -0
- package/test/fleetstore-smoke.js +152 -0
- package/webinterface/source/Pict-Application-Ultravisor.js +2 -0
- package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +4 -0
- package/webinterface/source/views/PictView-Ultravisor-Fleet.js +489 -0
- package/webinterface/source/views/PictView-Ultravisor-TopBar.js +1 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ultravisor Beacon Action Defaults
|
|
3
|
+
*
|
|
4
|
+
* Resolves per-action runtime defaults (timeout, retry policy, priority,
|
|
5
|
+
* expected-wait baseline) from the BeaconActionDefault table. Live
|
|
6
|
+
* config changes land here instead of in Fable settings, which means
|
|
7
|
+
* an operator can tune a slow capability without restarting the hub.
|
|
8
|
+
*
|
|
9
|
+
* Fallback order for any single field: per-request Settings → per-action
|
|
10
|
+
* row → per-capability row (Action="") → Fable setting → hard default.
|
|
11
|
+
* The last two levels are the compatibility shim while we migrate the
|
|
12
|
+
* scattered settings into rows.
|
|
13
|
+
*
|
|
14
|
+
* @module Ultravisor-Beacon-ActionDefaults
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const libPictService = require('pict-serviceproviderbase');
|
|
18
|
+
|
|
19
|
+
const HARD_DEFAULTS = {
|
|
20
|
+
TimeoutMs: 300000,
|
|
21
|
+
MaxAttempts: 1,
|
|
22
|
+
RetryBackoffMs: 5000,
|
|
23
|
+
DefaultPriority: 0,
|
|
24
|
+
ExpectedWaitP95Ms: 0,
|
|
25
|
+
HeartbeatExpectedMs: 60000,
|
|
26
|
+
MinSamplesForBaseline: 20
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class UltravisorBeaconActionDefaults extends libPictService
|
|
30
|
+
{
|
|
31
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
32
|
+
{
|
|
33
|
+
super(pPict, pOptions, pServiceHash);
|
|
34
|
+
this.serviceType = 'UltravisorBeaconActionDefaults';
|
|
35
|
+
this._Cache = {};
|
|
36
|
+
this._CacheTTLMs = 10000;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_getStore()
|
|
40
|
+
{
|
|
41
|
+
let tmpMap = this.fable.servicesMap && this.fable.servicesMap.UltravisorBeaconQueueStore;
|
|
42
|
+
if (!tmpMap) return null;
|
|
43
|
+
let tmpStore = Object.values(tmpMap)[0];
|
|
44
|
+
return (tmpStore && tmpStore.isEnabled()) ? tmpStore : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_cacheKey(pCap, pAction)
|
|
48
|
+
{
|
|
49
|
+
return `${pCap}||${pAction || ''}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_fableSettingFallback(pKey)
|
|
53
|
+
{
|
|
54
|
+
let tmpSettings = this.fable.settings || {};
|
|
55
|
+
// Legacy settings names kept during the migration period.
|
|
56
|
+
if (pKey === 'TimeoutMs' && tmpSettings.UltravisorBeaconWorkItemTimeoutMs)
|
|
57
|
+
{
|
|
58
|
+
return tmpSettings.UltravisorBeaconWorkItemTimeoutMs;
|
|
59
|
+
}
|
|
60
|
+
if (pKey === 'HeartbeatExpectedMs' && tmpSettings.UltravisorBeaconHeartbeatMs)
|
|
61
|
+
{
|
|
62
|
+
return tmpSettings.UltravisorBeaconHeartbeatMs;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
invalidate()
|
|
68
|
+
{
|
|
69
|
+
this._Cache = {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
resolve(pCapability, pAction)
|
|
73
|
+
{
|
|
74
|
+
let tmpKey = this._cacheKey(pCapability, pAction);
|
|
75
|
+
let tmpCached = this._Cache[tmpKey];
|
|
76
|
+
let tmpNow = Date.now();
|
|
77
|
+
if (tmpCached && (tmpNow - tmpCached.At) < this._CacheTTLMs)
|
|
78
|
+
{
|
|
79
|
+
return tmpCached.Value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let tmpStore = this._getStore();
|
|
83
|
+
let tmpSpecific = null;
|
|
84
|
+
let tmpWildcard = null;
|
|
85
|
+
if (tmpStore)
|
|
86
|
+
{
|
|
87
|
+
tmpSpecific = tmpStore.getActionDefault(pCapability, pAction || '');
|
|
88
|
+
if (!tmpSpecific && pAction)
|
|
89
|
+
{
|
|
90
|
+
tmpWildcard = tmpStore.getActionDefault(pCapability, '');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let tmpResolved = {};
|
|
95
|
+
for (let tmpField of Object.keys(HARD_DEFAULTS))
|
|
96
|
+
{
|
|
97
|
+
let tmpVal = null;
|
|
98
|
+
if (tmpSpecific && tmpSpecific[tmpField] != null && tmpSpecific[tmpField] !== 0)
|
|
99
|
+
{
|
|
100
|
+
tmpVal = tmpSpecific[tmpField];
|
|
101
|
+
}
|
|
102
|
+
else if (tmpWildcard && tmpWildcard[tmpField] != null && tmpWildcard[tmpField] !== 0)
|
|
103
|
+
{
|
|
104
|
+
tmpVal = tmpWildcard[tmpField];
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
tmpVal = this._fableSettingFallback(tmpField);
|
|
109
|
+
}
|
|
110
|
+
if (tmpVal == null) tmpVal = HARD_DEFAULTS[tmpField];
|
|
111
|
+
tmpResolved[tmpField] = tmpVal;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this._Cache[tmpKey] = { At: tmpNow, Value: tmpResolved };
|
|
115
|
+
return tmpResolved;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
applyToWorkItem(pWorkItem, pRequestSettings)
|
|
119
|
+
{
|
|
120
|
+
let tmpResolved = this.resolve(pWorkItem.Capability, pWorkItem.Action);
|
|
121
|
+
let tmpSettings = pRequestSettings || {};
|
|
122
|
+
|
|
123
|
+
pWorkItem.TimeoutMs = pWorkItem.TimeoutMs
|
|
124
|
+
|| parseInt(tmpSettings.timeoutMs, 10)
|
|
125
|
+
|| parseInt(tmpSettings.TimeoutMs, 10)
|
|
126
|
+
|| tmpResolved.TimeoutMs;
|
|
127
|
+
|
|
128
|
+
pWorkItem.MaxAttempts = pWorkItem.MaxAttempts
|
|
129
|
+
|| parseInt(tmpSettings.maxRetries, 10)
|
|
130
|
+
|| parseInt(tmpSettings.MaxAttempts, 10)
|
|
131
|
+
|| tmpResolved.MaxAttempts;
|
|
132
|
+
|
|
133
|
+
pWorkItem.RetryBackoffMs = pWorkItem.RetryBackoffMs
|
|
134
|
+
|| parseInt(tmpSettings.retryBackoffMs, 10)
|
|
135
|
+
|| parseInt(tmpSettings.RetryBackoffMs, 10)
|
|
136
|
+
|| tmpResolved.RetryBackoffMs;
|
|
137
|
+
|
|
138
|
+
if (pWorkItem.Priority == null)
|
|
139
|
+
{
|
|
140
|
+
let tmpPri = parseInt(tmpSettings.priority, 10);
|
|
141
|
+
if (isNaN(tmpPri)) tmpPri = parseInt(tmpSettings.Priority, 10);
|
|
142
|
+
if (isNaN(tmpPri)) tmpPri = tmpResolved.DefaultPriority;
|
|
143
|
+
pWorkItem.Priority = tmpPri;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return pWorkItem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Compute a live p95 estimate from the last N completed samples.
|
|
151
|
+
* Used when no ExpectedWaitP95Ms is set on the row yet. Stored
|
|
152
|
+
* back into the row so future lookups are fast.
|
|
153
|
+
*/
|
|
154
|
+
recomputeWaitBaseline(pCapability, pAction, pMinSamples)
|
|
155
|
+
{
|
|
156
|
+
let tmpStore = this._getStore();
|
|
157
|
+
if (!tmpStore) return null;
|
|
158
|
+
let tmpMin = pMinSamples || HARD_DEFAULTS.MinSamplesForBaseline;
|
|
159
|
+
let tmpSamples = tmpStore.queueWaitSamples(pCapability, pAction || '', 500);
|
|
160
|
+
if (tmpSamples.length < tmpMin) return null;
|
|
161
|
+
tmpSamples.sort((a, b) => a - b);
|
|
162
|
+
let tmpIdx = Math.max(0, Math.floor(tmpSamples.length * 0.95) - 1);
|
|
163
|
+
let tmpP95 = tmpSamples[tmpIdx];
|
|
164
|
+
tmpStore.upsertActionDefault({
|
|
165
|
+
Capability: pCapability,
|
|
166
|
+
Action: pAction || '',
|
|
167
|
+
ExpectedWaitP95Ms: tmpP95
|
|
168
|
+
});
|
|
169
|
+
this.invalidate();
|
|
170
|
+
return tmpP95;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
module.exports = UltravisorBeaconActionDefaults;
|