@certik/skynet 0.10.5 → 0.10.8
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/.eslintrc.js +5 -5
- package/CHANGELOG.md +13 -0
- package/ably.js +29 -0
- package/api.js +31 -8
- package/app.js +20 -6
- package/deploy.js +1 -1
- package/examples/api +7 -10
- package/indexer.js +35 -34
- package/kafka.js +15 -13
- package/monitor.js +5 -8
- package/package.json +5 -2
package/.eslintrc.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
env: {
|
|
3
3
|
node: true,
|
|
4
|
-
browser:
|
|
4
|
+
browser: false,
|
|
5
5
|
commonjs: true,
|
|
6
|
-
es2021: true
|
|
6
|
+
es2021: true,
|
|
7
7
|
},
|
|
8
|
-
extends: "eslint:recommended",
|
|
8
|
+
extends: ["eslint:recommended", "plugin:import/recommended"],
|
|
9
9
|
parserOptions: {
|
|
10
|
-
ecmaVersion: 12
|
|
10
|
+
ecmaVersion: 12,
|
|
11
11
|
},
|
|
12
|
-
rules: {}
|
|
12
|
+
rules: {},
|
|
13
13
|
};
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.8
|
|
4
|
+
|
|
5
|
+
- Added logMiddleware to `api` apps by default
|
|
6
|
+
- Enabled opensearch logging for log-shipper
|
|
7
|
+
|
|
8
|
+
## 0.10.7
|
|
9
|
+
|
|
10
|
+
- Added `ably` library
|
|
11
|
+
|
|
12
|
+
## 0.10.6
|
|
13
|
+
|
|
14
|
+
- Fixed producer check function
|
|
15
|
+
|
|
3
16
|
## 0.10.5
|
|
4
17
|
|
|
5
18
|
- BREAKING Changed the signature of `postGenieMessage` function in `opsgenie` to make it more customizable
|
package/ably.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const Ably = require("ably");
|
|
2
|
+
const Bottleneck = require("bottleneck/es5");
|
|
3
|
+
const { ensureAndGet } = require("./env");
|
|
4
|
+
|
|
5
|
+
const ably = new Ably.Realtime(ensureAndGet("ABLY_ROOT_API_KEY"));
|
|
6
|
+
ably.connection.on("connected", () => {
|
|
7
|
+
console.log("ably connection successful");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
async function publishMessage(channel, messageName, messageData) {
|
|
11
|
+
const channelObj = ably.channels.get(channel);
|
|
12
|
+
|
|
13
|
+
const messageDataJson = JSON.stringify(messageData);
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
await channelObj.publish(messageName, messageDataJson);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error("error publishing to ably: ", error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const rateLimitedPublishMessage = new Bottleneck({
|
|
23
|
+
minTime: 1000 / 50,
|
|
24
|
+
}).wrap(publishMessage);
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
publishMessage,
|
|
28
|
+
rateLimitedPublishMessage,
|
|
29
|
+
};
|
package/api.js
CHANGED
|
@@ -2,6 +2,25 @@ const express = require("express");
|
|
|
2
2
|
const meow = require("meow");
|
|
3
3
|
const { getSelectorFlags, getSelectorDesc } = require("./selector");
|
|
4
4
|
const { isProduction } = require("./env");
|
|
5
|
+
const { inline } = require("./log");
|
|
6
|
+
|
|
7
|
+
async function logMiddleware(req, res, next) {
|
|
8
|
+
const start = new Date();
|
|
9
|
+
next();
|
|
10
|
+
const end = new Date();
|
|
11
|
+
const logInfo = {
|
|
12
|
+
start,
|
|
13
|
+
end,
|
|
14
|
+
elapsed: `${end - start}ms`,
|
|
15
|
+
endpoint: req.path,
|
|
16
|
+
host: req.hostname,
|
|
17
|
+
status: res.statusCode,
|
|
18
|
+
};
|
|
19
|
+
if (res.statusMessage) {
|
|
20
|
+
logInfo.errorMessage = res.statusMessage;
|
|
21
|
+
}
|
|
22
|
+
inline.log(JSON.stringify(logInfo));
|
|
23
|
+
}
|
|
5
24
|
|
|
6
25
|
const apiKeyMiddleware = (key) => {
|
|
7
26
|
async function requireAPIKey(req, res, next) {
|
|
@@ -9,7 +28,7 @@ const apiKeyMiddleware = (key) => {
|
|
|
9
28
|
const apiKey = req.get("x-api-key");
|
|
10
29
|
|
|
11
30
|
if (!apiKey) {
|
|
12
|
-
|
|
31
|
+
inline.log("request without api key");
|
|
13
32
|
|
|
14
33
|
res.status(400).send("require x-api-key header");
|
|
15
34
|
|
|
@@ -17,7 +36,7 @@ const apiKeyMiddleware = (key) => {
|
|
|
17
36
|
}
|
|
18
37
|
|
|
19
38
|
if (apiKey !== key) {
|
|
20
|
-
|
|
39
|
+
inline.log("request has an invalid api key");
|
|
21
40
|
|
|
22
41
|
res.status(400).send("invalid api key");
|
|
23
42
|
|
|
@@ -26,7 +45,7 @@ const apiKeyMiddleware = (key) => {
|
|
|
26
45
|
|
|
27
46
|
next();
|
|
28
47
|
} catch (err) {
|
|
29
|
-
|
|
48
|
+
inline.log("check api key error", err);
|
|
30
49
|
|
|
31
50
|
res.status(500).send("internal error");
|
|
32
51
|
}
|
|
@@ -72,20 +91,24 @@ ${getSelectorDesc(selector)}
|
|
|
72
91
|
const method = route.method ? route.method.toLowerCase() : "get";
|
|
73
92
|
const middlewares = route.middlewares || [];
|
|
74
93
|
|
|
94
|
+
if (route.log !== false) {
|
|
95
|
+
middlewares.unshift(logMiddleware);
|
|
96
|
+
}
|
|
97
|
+
|
|
75
98
|
if (route.protected) {
|
|
76
|
-
middlewares.
|
|
99
|
+
middlewares.unshift(apiKeyMiddleware(serve.apiKey));
|
|
77
100
|
}
|
|
78
101
|
|
|
79
102
|
if (app[method]) {
|
|
80
103
|
if (verbose) {
|
|
81
|
-
|
|
104
|
+
inline.log(`registering ${method} ${route.path}`);
|
|
82
105
|
}
|
|
83
106
|
|
|
84
107
|
app[method](route.path, ...middlewares, async (req, res) => {
|
|
85
108
|
try {
|
|
86
109
|
await route.handler({ req, res, ...selectorFlags });
|
|
87
110
|
} catch (routeErr) {
|
|
88
|
-
|
|
111
|
+
inline.log("caught route err", routeErr);
|
|
89
112
|
|
|
90
113
|
res.status(500).send(`internal server error: ${routeErr.message}`);
|
|
91
114
|
}
|
|
@@ -95,9 +118,9 @@ ${getSelectorDesc(selector)}
|
|
|
95
118
|
|
|
96
119
|
app.listen(serve.port, () => {
|
|
97
120
|
if (isProduction()) {
|
|
98
|
-
|
|
121
|
+
inline.log(`${name} listening at https://api.certik-skynet.com/${serve.prefix}`);
|
|
99
122
|
} else {
|
|
100
|
-
|
|
123
|
+
inline.log(`${name} listening at http://localhost:${serve.port}`);
|
|
101
124
|
}
|
|
102
125
|
});
|
|
103
126
|
}
|
package/app.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
const { EOL } = require("os");
|
|
2
2
|
const fetch = require("node-fetch");
|
|
3
3
|
const { SKYNET_API_PREFIX } = require("./const");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
createIndexerApp,
|
|
6
|
+
createModeIndexerApp,
|
|
7
|
+
getIndexerLatestId,
|
|
8
|
+
getIndexerValidatedId,
|
|
9
|
+
getIndexerState,
|
|
10
|
+
} = require("./indexer");
|
|
5
11
|
const { createDeploy, createModeDeploy } = require("./deploy");
|
|
6
|
-
const { createProducerApp, createConsumerApp } = require("./kafka");
|
|
12
|
+
const { createProducerApp, createConsumerApp, getProducerLatestId } = require("./kafka");
|
|
7
13
|
const { startApiApp } = require("./api");
|
|
8
14
|
const { createMonitor, ERROR_LEVEL } = require("./monitor");
|
|
9
15
|
const { getBinaryName, detectBin, detectWorkingDirectory } = require("./cli");
|
|
@@ -326,7 +332,13 @@ function modeIndexer({ name, selector, state, build, validate, check, env = {},
|
|
|
326
332
|
const { monitor } = createMonitor({
|
|
327
333
|
binaryName: `${getBinaryName()} check`,
|
|
328
334
|
name,
|
|
329
|
-
|
|
335
|
+
getState: async (nam, selectorFlags) => {
|
|
336
|
+
const latestId = await getIndexerLatestId(nam, selectorFlags);
|
|
337
|
+
const validatedId = await getIndexerValidatedId(nam, selectorFlags);
|
|
338
|
+
const buildState = await getIndexerState(nam, selectorFlags);
|
|
339
|
+
|
|
340
|
+
return { latestId, validatedId, buildState };
|
|
341
|
+
},
|
|
330
342
|
selector,
|
|
331
343
|
mode: true,
|
|
332
344
|
check: check.func,
|
|
@@ -428,7 +440,11 @@ function producer({ name, selector, produce, check, state, env = {}, region = "u
|
|
|
428
440
|
const { monitor } = createMonitor({
|
|
429
441
|
binaryName: `${getBinaryName()} check`,
|
|
430
442
|
name,
|
|
431
|
-
|
|
443
|
+
getState: async (nam, selectorFlags) => {
|
|
444
|
+
const latestId = await getProducerLatestId(nam, selectorFlags);
|
|
445
|
+
|
|
446
|
+
return { latestId };
|
|
447
|
+
},
|
|
432
448
|
selector,
|
|
433
449
|
check: check.func,
|
|
434
450
|
maxRetry: check.maxRetry,
|
|
@@ -520,7 +536,6 @@ function consumer({ name, selector, consume, check, env = {}, region = "us-east-
|
|
|
520
536
|
const { monitor } = createMonitor({
|
|
521
537
|
binaryName: `${getBinaryName()} check`,
|
|
522
538
|
name,
|
|
523
|
-
type: "stateless",
|
|
524
539
|
selector,
|
|
525
540
|
check: check.func,
|
|
526
541
|
maxRetry: check.maxRetry,
|
|
@@ -660,7 +675,6 @@ function api({ name, routes, serve, env = {}, region = "us-east-1" }) {
|
|
|
660
675
|
const { monitor } = createMonitor({
|
|
661
676
|
binaryName: `${getBinaryName()} check`,
|
|
662
677
|
name,
|
|
663
|
-
type: "stateless",
|
|
664
678
|
selector,
|
|
665
679
|
check: check.func,
|
|
666
680
|
maxRetry: check.maxRetry,
|
package/deploy.js
CHANGED
|
@@ -102,7 +102,7 @@ const genConfig = ({
|
|
|
102
102
|
command = "sh"
|
|
103
103
|
args = [
|
|
104
104
|
"-c",
|
|
105
|
-
"cd \${meta.skynet_code_path}/infra-nomad/log-shipper && yarn install --silent && exec bin/shipper --path ${jobName}"
|
|
105
|
+
"cd \${meta.skynet_code_path}/infra-nomad/log-shipper && yarn install --silent && exec bin/shipper --path ${jobName} --opensearch"
|
|
106
106
|
]
|
|
107
107
|
}
|
|
108
108
|
|
package/examples/api
CHANGED
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
// this file is executable and is for kafka producer testing
|
|
4
4
|
// a few test commands to try on
|
|
5
|
-
// $ examples/api run --verbose
|
|
6
|
-
// $ examples/api run
|
|
7
|
-
// $ examples/api check
|
|
5
|
+
// $ EXAMPLE_API_KEY=abc examples/api run --verbose
|
|
6
|
+
// $ EXAMPLE_API_KEY=abc examples/api run
|
|
8
7
|
// $ examples/api deploy
|
|
9
8
|
// $ examples/api --help
|
|
10
9
|
|
|
11
10
|
const { api, every, SENSITIVE_VALUE, ERROR_LEVEL } = require("../app");
|
|
12
11
|
|
|
13
12
|
// an example middleware
|
|
14
|
-
async function
|
|
15
|
-
|
|
13
|
+
async function exampleMiddleware(req, res, next) {
|
|
14
|
+
console.log("before request!");
|
|
16
15
|
next();
|
|
17
|
-
|
|
18
|
-
const logInfo = { start, end, elapsed: `${end - start}ms` };
|
|
19
|
-
console.log(logInfo);
|
|
16
|
+
console.log("after request!");
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
async function getProjectsHandler({ req, res, verbose }) {
|
|
@@ -50,14 +47,14 @@ const app = api({
|
|
|
50
47
|
method: "GET",
|
|
51
48
|
path: "/projects",
|
|
52
49
|
handler: getProjectsHandler,
|
|
53
|
-
middlewares: [
|
|
50
|
+
middlewares: [exampleMiddleware],
|
|
54
51
|
},
|
|
55
52
|
{
|
|
56
53
|
method: "POST",
|
|
57
54
|
path: "/projects",
|
|
58
55
|
handler: createProjectHandler,
|
|
59
56
|
protected: true,
|
|
60
|
-
middlewares: [
|
|
57
|
+
middlewares: [exampleMiddleware],
|
|
61
58
|
},
|
|
62
59
|
],
|
|
63
60
|
|
package/indexer.js
CHANGED
|
@@ -5,6 +5,7 @@ const { exponentialRetry } = require("./availability");
|
|
|
5
5
|
const { range, fillRange } = require("./util");
|
|
6
6
|
const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
|
|
7
7
|
const { getBinaryName } = require("./cli");
|
|
8
|
+
const { inline } = require("./log");
|
|
8
9
|
|
|
9
10
|
const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
|
|
10
11
|
|
|
@@ -90,7 +91,7 @@ function createModeIndexerApp({
|
|
|
90
91
|
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
91
92
|
});
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
inline.log(`RebuildState=${stateItem?.value} Since=${fromItem?.value} Validated=${validateItem?.value}`);
|
|
94
95
|
|
|
95
96
|
process.exit(0);
|
|
96
97
|
}
|
|
@@ -99,7 +100,7 @@ function createModeIndexerApp({
|
|
|
99
100
|
from = await finalState.getMinId(selectorFlags);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
inline.log(
|
|
103
104
|
`[MODE INDEXER] mode=${mode}, from=${from}, to=${
|
|
104
105
|
to > 0 ? to : "undefined"
|
|
105
106
|
}, env=${getEnvironment()}, ${toSelectorString(selectorFlags, ", ")}`
|
|
@@ -135,7 +136,7 @@ function createModeIndexerApp({
|
|
|
135
136
|
);
|
|
136
137
|
} else if (mode === "one") {
|
|
137
138
|
if (to > 0) {
|
|
138
|
-
|
|
139
|
+
inline.log("[MODE INDEXER] one mode ignores --to option. you may want to use range mode instead");
|
|
139
140
|
}
|
|
140
141
|
await runRange(selectorFlags, from, from, verbose);
|
|
141
142
|
} else if (mode === "range") {
|
|
@@ -148,7 +149,7 @@ function createModeIndexerApp({
|
|
|
148
149
|
async function runRange(selectorFlags, from, to, verbose) {
|
|
149
150
|
const startTime = Date.now();
|
|
150
151
|
|
|
151
|
-
|
|
152
|
+
inline.log(
|
|
152
153
|
`[MODE INDEXER] building range, from=${from}, to=${to}, ${toSelectorString(
|
|
153
154
|
selectorFlags,
|
|
154
155
|
", "
|
|
@@ -158,23 +159,23 @@ function createModeIndexerApp({
|
|
|
158
159
|
const failedIds = await execBuild(selectorFlags, from, to, verbose, false);
|
|
159
160
|
|
|
160
161
|
if (failedIds.length > 0) {
|
|
161
|
-
|
|
162
|
+
inline.log(`[MODE INDEXER] built with some failed ${finalState.type}`, failedIds);
|
|
162
163
|
process.exit(1);
|
|
163
164
|
} else {
|
|
164
|
-
|
|
165
|
+
inline.log(`[MODE INDEXER] built successfully in ${Date.now() - startTime}ms`);
|
|
165
166
|
process.exit(0);
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
async function runValidate(selectorFlags, from, to, shouldSaveState, verbose) {
|
|
170
171
|
if (!validate) {
|
|
171
|
-
|
|
172
|
+
inline.log(`[MODE INDEXER] the indexer doesn't support validate mode, validate function not implemented`);
|
|
172
173
|
process.exit(1);
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
const startTime = Date.now();
|
|
176
177
|
|
|
177
|
-
|
|
178
|
+
inline.log(
|
|
178
179
|
`[MODE INDEXER] validating, from=${from}, to=${to}, ${toSelectorString(
|
|
179
180
|
selectorFlags,
|
|
180
181
|
", "
|
|
@@ -183,12 +184,12 @@ function createModeIndexerApp({
|
|
|
183
184
|
|
|
184
185
|
const windows = range(from, to, validateBatchSize * validateConcurrency);
|
|
185
186
|
|
|
186
|
-
|
|
187
|
+
inline.log(
|
|
187
188
|
`[MODE INDEXER] from=${from}, to=${to}, batchSize=${validateBatchSize}, concurrency=${validateConcurrency}`
|
|
188
189
|
);
|
|
189
190
|
|
|
190
191
|
for (let [windowStart, windowEnd] of windows) {
|
|
191
|
-
|
|
192
|
+
inline.log(`[MODE INDEXER] validating window ${windowStart}~${windowEnd}, concurrency=${validateConcurrency}`);
|
|
192
193
|
|
|
193
194
|
const batches = range(windowStart, windowEnd, validateBatchSize);
|
|
194
195
|
|
|
@@ -207,7 +208,7 @@ function createModeIndexerApp({
|
|
|
207
208
|
|
|
208
209
|
return true;
|
|
209
210
|
} catch (err) {
|
|
210
|
-
|
|
211
|
+
inline.error(`got error in validation`, err);
|
|
211
212
|
|
|
212
213
|
return false;
|
|
213
214
|
}
|
|
@@ -232,12 +233,12 @@ function createModeIndexerApp({
|
|
|
232
233
|
});
|
|
233
234
|
|
|
234
235
|
if (verbose) {
|
|
235
|
-
|
|
236
|
+
inline.log(`[MODE INDEXER] updated processed ${finalState.type} to ${windowEnd}`);
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
+
inline.log(
|
|
241
242
|
`[MODE INDEXER] validated ${to - from + 1} ${finalState.type} successfully in ${Date.now() - startTime}ms`
|
|
242
243
|
);
|
|
243
244
|
}
|
|
@@ -248,7 +249,7 @@ function createModeIndexerApp({
|
|
|
248
249
|
const windows = range(from, to, buildBatchSize * buildConcurrency);
|
|
249
250
|
|
|
250
251
|
for (let [windowStart, windowEnd] of windows) {
|
|
251
|
-
|
|
252
|
+
inline.log(`[MODE INDEXER] building window ${windowStart}~${windowEnd}, concurrency = ${buildConcurrency}`);
|
|
252
253
|
|
|
253
254
|
const batches = range(windowStart, windowEnd, buildBatchSize);
|
|
254
255
|
|
|
@@ -271,7 +272,7 @@ function createModeIndexerApp({
|
|
|
271
272
|
return false;
|
|
272
273
|
}
|
|
273
274
|
} catch (err) {
|
|
274
|
-
|
|
275
|
+
inline.error(`[MODE INDEXER] got error in build`, err);
|
|
275
276
|
|
|
276
277
|
return fillRange(batchStart, batchEnd);
|
|
277
278
|
}
|
|
@@ -292,7 +293,7 @@ function createModeIndexerApp({
|
|
|
292
293
|
});
|
|
293
294
|
|
|
294
295
|
if (verbose) {
|
|
295
|
-
|
|
296
|
+
inline.log(`[MODE INDEXER] updated processed ${finalState.type} to ${windowEnd}`);
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
|
|
@@ -311,7 +312,7 @@ function createModeIndexerApp({
|
|
|
311
312
|
async function runRebuild(selectorFlags, from, to, verbose) {
|
|
312
313
|
const startTime = Date.now();
|
|
313
314
|
|
|
314
|
-
|
|
315
|
+
inline.log(
|
|
315
316
|
`[MODE INDEXER] rebuilding, from=${from}, to=${to}, ${toSelectorString(
|
|
316
317
|
selectorFlags,
|
|
317
318
|
", "
|
|
@@ -339,13 +340,13 @@ function createModeIndexerApp({
|
|
|
339
340
|
});
|
|
340
341
|
|
|
341
342
|
if (failedIds.length > 0) {
|
|
342
|
-
|
|
343
|
+
inline.log(
|
|
343
344
|
`[MODE INDEXER] built ${to - from + 1} ${finalState.type} with some failed ${finalState.type}`,
|
|
344
345
|
failedIds
|
|
345
346
|
);
|
|
346
347
|
process.exit(1);
|
|
347
348
|
} else {
|
|
348
|
-
|
|
349
|
+
inline.log(
|
|
349
350
|
`[MODE INDEXER] built ${to - from + 1} ${finalState.type} successfully in ${Date.now() - startTime}ms`
|
|
350
351
|
);
|
|
351
352
|
process.exit(0);
|
|
@@ -365,7 +366,7 @@ function createModeIndexerApp({
|
|
|
365
366
|
const to = await state.getMaxId(selectorFlags);
|
|
366
367
|
|
|
367
368
|
if (to <= from) {
|
|
368
|
-
|
|
369
|
+
inline.log(
|
|
369
370
|
`[MODE INDEXER] skip delta because there're no items need to be processed, ${toSelectorString(
|
|
370
371
|
selectorFlags,
|
|
371
372
|
", "
|
|
@@ -375,7 +376,7 @@ function createModeIndexerApp({
|
|
|
375
376
|
return;
|
|
376
377
|
}
|
|
377
378
|
|
|
378
|
-
|
|
379
|
+
inline.log(
|
|
379
380
|
`[MODE INDEXER] starting delta, from=${from}, to=${to}, ${toSelectorString(
|
|
380
381
|
selectorFlags,
|
|
381
382
|
", "
|
|
@@ -386,7 +387,7 @@ function createModeIndexerApp({
|
|
|
386
387
|
const failedIds = await execBuild(selectorFlags, from, to, verbose, true);
|
|
387
388
|
|
|
388
389
|
if (failedIds.length > 0) {
|
|
389
|
-
|
|
390
|
+
inline.log("[MODE INDEXER] built with some failed txs", failedIds);
|
|
390
391
|
|
|
391
392
|
await createRecord(STATE_TABLE_NAME, {
|
|
392
393
|
name: `${name}DeltaState(${toSelectorString(selectorFlags)})`,
|
|
@@ -410,25 +411,25 @@ function createModeIndexerApp({
|
|
|
410
411
|
value: to,
|
|
411
412
|
});
|
|
412
413
|
|
|
413
|
-
|
|
414
|
+
inline.log(`[MODE INDEXER] built successfully in ${Date.now() - startTime}ms`);
|
|
414
415
|
process.exit(0);
|
|
415
416
|
}
|
|
416
417
|
} catch (err) {
|
|
417
|
-
|
|
418
|
+
inline.error("[MODE INDEXER] delta build failed", from, to, err);
|
|
418
419
|
|
|
419
420
|
process.exit(1);
|
|
420
421
|
}
|
|
421
422
|
} else {
|
|
422
|
-
|
|
423
|
+
inline.log("[MODE INDEXER] skip because rebuild hasn't done yet");
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
426
|
|
|
426
427
|
async function runReset(selectorFlags) {
|
|
427
428
|
const startTime = Date.now();
|
|
428
429
|
|
|
429
|
-
|
|
430
|
+
inline.log(`[MODE INDEXER] starting reset, ${toSelectorString(selectorFlags, ", ")}`);
|
|
430
431
|
|
|
431
|
-
|
|
432
|
+
inline.log("[MODE INDEXER] reset state", STATE_TABLE_NAME);
|
|
432
433
|
await createRecord(STATE_TABLE_NAME, {
|
|
433
434
|
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
434
435
|
value: 0,
|
|
@@ -444,7 +445,7 @@ function createModeIndexerApp({
|
|
|
444
445
|
value: "init",
|
|
445
446
|
});
|
|
446
447
|
|
|
447
|
-
|
|
448
|
+
inline.log(`[MODE INDEXER] reset successfully in ${Date.now() - startTime}ms`);
|
|
448
449
|
}
|
|
449
450
|
|
|
450
451
|
function run() {
|
|
@@ -498,7 +499,7 @@ ${getSelectorDesc(selector)}
|
|
|
498
499
|
);
|
|
499
500
|
|
|
500
501
|
runMode(cli.flags).catch((err) => {
|
|
501
|
-
|
|
502
|
+
inline.error(err);
|
|
502
503
|
process.exit(1);
|
|
503
504
|
});
|
|
504
505
|
}
|
|
@@ -541,9 +542,9 @@ ${getSelectorDesc(selector)}
|
|
|
541
542
|
const startTime = Date.now();
|
|
542
543
|
|
|
543
544
|
if (Object.keys(selectorFlags).length > 0) {
|
|
544
|
-
|
|
545
|
+
inline.log(`[INDEXER] starting build, ${toSelectorString(selectorFlags, ", ")}`);
|
|
545
546
|
} else {
|
|
546
|
-
|
|
547
|
+
inline.log(`[INDEXER] starting build`);
|
|
547
548
|
}
|
|
548
549
|
|
|
549
550
|
const result = await exponentialRetry(
|
|
@@ -553,7 +554,7 @@ ${getSelectorDesc(selector)}
|
|
|
553
554
|
|
|
554
555
|
return true;
|
|
555
556
|
} catch (err) {
|
|
556
|
-
|
|
557
|
+
inline.log(`[INDEXER] got error in build`, err);
|
|
557
558
|
|
|
558
559
|
return false;
|
|
559
560
|
}
|
|
@@ -574,11 +575,11 @@ ${getSelectorDesc(selector)}
|
|
|
574
575
|
value: new Date().toISOString(),
|
|
575
576
|
});
|
|
576
577
|
|
|
577
|
-
|
|
578
|
+
inline.log(`[INDEXER] build successfully in ${Date.now() - startTime}ms`);
|
|
578
579
|
}
|
|
579
580
|
|
|
580
581
|
runBuild(cli.flags).catch((err) => {
|
|
581
|
-
|
|
582
|
+
inline.error(err);
|
|
582
583
|
process.exit(1);
|
|
583
584
|
});
|
|
584
585
|
}
|
package/kafka.js
CHANGED
|
@@ -6,6 +6,7 @@ const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selec
|
|
|
6
6
|
const { createRecord, getRecordByKey, deleteRecordsByHashKey } = require("./dynamodb");
|
|
7
7
|
const { exponentialRetry } = require("./availability");
|
|
8
8
|
const { getBinaryName } = require("./cli");
|
|
9
|
+
const { inline } = require("./log");
|
|
9
10
|
|
|
10
11
|
const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
|
|
11
12
|
|
|
@@ -35,7 +36,7 @@ async function deleteProducerLatestId(name, selectorFlags, verbose) {
|
|
|
35
36
|
function sendToTopic(producer, topic, verbose) {
|
|
36
37
|
async function send(records) {
|
|
37
38
|
if (verbose) {
|
|
38
|
-
|
|
39
|
+
inline.log(`sending ${records.length} records to topic`, records);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
await producer.send({
|
|
@@ -204,7 +205,7 @@ ${getSelectorDesc(selector)}
|
|
|
204
205
|
await finalState.onReset(selectorFlags, verbose);
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
|
|
208
|
+
inline.log("producer reset");
|
|
208
209
|
|
|
209
210
|
process.exit(0);
|
|
210
211
|
}
|
|
@@ -212,7 +213,7 @@ ${getSelectorDesc(selector)}
|
|
|
212
213
|
if (status) {
|
|
213
214
|
const latestId = await getProducerLatestId(name, selectorFlags);
|
|
214
215
|
|
|
215
|
-
|
|
216
|
+
inline.log(`LatestID=${latestId}`);
|
|
216
217
|
|
|
217
218
|
process.exit(0);
|
|
218
219
|
}
|
|
@@ -239,7 +240,7 @@ ${getSelectorDesc(selector)}
|
|
|
239
240
|
|
|
240
241
|
const producerInstance = await initProducer(name, kafkaCredential);
|
|
241
242
|
|
|
242
|
-
|
|
243
|
+
inline.log("producing to topic", finalTopic);
|
|
243
244
|
|
|
244
245
|
// if to flag was not provided, run this program indefinitely
|
|
245
246
|
const isLongRunning = to === 0;
|
|
@@ -275,7 +276,7 @@ ${getSelectorDesc(selector)}
|
|
|
275
276
|
const batchStart = i;
|
|
276
277
|
const batchEnd = Math.min(batchStart + batchSize - 1, lastId);
|
|
277
278
|
|
|
278
|
-
|
|
279
|
+
inline.log(`building batch ${batchStart}~${batchEnd}`);
|
|
279
280
|
|
|
280
281
|
// add a retry for errors
|
|
281
282
|
const result = await exponentialRetry(
|
|
@@ -295,7 +296,7 @@ ${getSelectorDesc(selector)}
|
|
|
295
296
|
|
|
296
297
|
return true;
|
|
297
298
|
} catch (err) {
|
|
298
|
-
|
|
299
|
+
inline.error(`Critical error processing batch ${batchStart}~${batchEnd}`, err);
|
|
299
300
|
|
|
300
301
|
return false;
|
|
301
302
|
}
|
|
@@ -330,7 +331,7 @@ ${getSelectorDesc(selector)}
|
|
|
330
331
|
}
|
|
331
332
|
|
|
332
333
|
return build(cli.flags).catch((err) => {
|
|
333
|
-
|
|
334
|
+
inline.error(err);
|
|
334
335
|
process.exit(1);
|
|
335
336
|
});
|
|
336
337
|
}
|
|
@@ -381,12 +382,12 @@ ${getSelectorDesc(selector)}
|
|
|
381
382
|
|
|
382
383
|
await consumerInstance.subscribe({ topic: finalTopic });
|
|
383
384
|
|
|
384
|
-
|
|
385
|
+
inline.log("subscribed to topic", finalTopic);
|
|
385
386
|
|
|
386
387
|
await consumerInstance.run({
|
|
387
388
|
eachBatch: async ({ batch }) => {
|
|
388
389
|
if (verbose) {
|
|
389
|
-
|
|
390
|
+
inline.log("received batch, number of items =", batch.messages.length);
|
|
390
391
|
}
|
|
391
392
|
|
|
392
393
|
const messages = batch.messages.map((m) => JSON.parse(m.value));
|
|
@@ -399,7 +400,7 @@ ${getSelectorDesc(selector)}
|
|
|
399
400
|
|
|
400
401
|
return true;
|
|
401
402
|
} catch (err) {
|
|
402
|
-
|
|
403
|
+
inline.error(`got critical error`, err);
|
|
403
404
|
|
|
404
405
|
return false;
|
|
405
406
|
}
|
|
@@ -412,21 +413,21 @@ ${getSelectorDesc(selector)}
|
|
|
412
413
|
);
|
|
413
414
|
|
|
414
415
|
if (!result) {
|
|
415
|
-
|
|
416
|
+
inline.error("Terminate consumer due to consume errors, likely bug");
|
|
416
417
|
|
|
417
418
|
process.exit(1);
|
|
418
419
|
}
|
|
419
420
|
},
|
|
420
421
|
});
|
|
421
422
|
} catch (err) {
|
|
422
|
-
|
|
423
|
+
inline.error("Terminate consumer due to critical kafka connection error", err);
|
|
423
424
|
|
|
424
425
|
process.exit(1);
|
|
425
426
|
}
|
|
426
427
|
}
|
|
427
428
|
|
|
428
429
|
return build(cli.flags).catch((err) => {
|
|
429
|
-
|
|
430
|
+
inline.error(err);
|
|
430
431
|
process.exit(1);
|
|
431
432
|
});
|
|
432
433
|
}
|
|
@@ -439,4 +440,5 @@ module.exports = {
|
|
|
439
440
|
createConsumerApp,
|
|
440
441
|
produceMessages,
|
|
441
442
|
consumeMessages,
|
|
443
|
+
getProducerLatestId,
|
|
442
444
|
};
|
package/monitor.js
CHANGED
|
@@ -3,7 +3,6 @@ const fetch = require("node-fetch");
|
|
|
3
3
|
const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
|
|
4
4
|
const { getBinaryName } = require("./cli");
|
|
5
5
|
const { exponentialRetry } = require("./availability");
|
|
6
|
-
const { getIndexerLatestId, getIndexerValidatedId, getIndexerState } = require("./indexer");
|
|
7
6
|
const { postGenieMessage } = require("./opsgenie");
|
|
8
7
|
const { getJobName } = require("./deploy");
|
|
9
8
|
|
|
@@ -67,7 +66,7 @@ async function getMostRecentJobLaunch(name) {
|
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
function createMonitor({ binaryName, name,
|
|
69
|
+
function createMonitor({ binaryName, name, getState = null, mode = false, selector = {}, check, maxRetry = 2 }) {
|
|
71
70
|
function monitor() {
|
|
72
71
|
if (!binaryName) {
|
|
73
72
|
binaryName = getBinaryName();
|
|
@@ -109,18 +108,16 @@ ${
|
|
|
109
108
|
const startTime = Date.now();
|
|
110
109
|
console.log(`[MONITOR] starting check, ${toSelectorString(selectorFlags, ", ")}`);
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
let checkState = {};
|
|
113
112
|
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
state.validatedId = await getIndexerValidatedId(name, selectorFlags);
|
|
117
|
-
state.buildState = await getIndexerState(name, selectorFlags);
|
|
113
|
+
if (getState) {
|
|
114
|
+
checkState = await getState(name, selectorFlags);
|
|
118
115
|
}
|
|
119
116
|
|
|
120
117
|
let result = await exponentialRetry(
|
|
121
118
|
async () => {
|
|
122
119
|
try {
|
|
123
|
-
const errors = await check({ verbose, state, mode, ...selectorFlags });
|
|
120
|
+
const errors = await check({ verbose, state: checkState, mode, ...selectorFlags });
|
|
124
121
|
|
|
125
122
|
if (!Array.isArray(errors)) {
|
|
126
123
|
throw new Error(`check function must return array of error messages`);
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certik/skynet",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.8",
|
|
4
4
|
"description": "Skynet Shared JS library",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "CertiK Engineering",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"lint": "eslint
|
|
8
|
+
"lint": "eslint *.js test",
|
|
9
9
|
"test": "ava"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@slack/web-api": "^6.4.0",
|
|
16
|
+
"ably": "^1.2.22",
|
|
16
17
|
"aws-sdk": "^2.932.0",
|
|
18
|
+
"bottleneck": "^2.19.5",
|
|
17
19
|
"chalk": "^4.1.1",
|
|
18
20
|
"execa": "^5.0.0",
|
|
19
21
|
"express": "^4.18.1",
|
|
@@ -28,6 +30,7 @@
|
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"ava": "^3.13.0",
|
|
30
32
|
"eslint": "^7.22.0",
|
|
33
|
+
"eslint-plugin-import": "^2.26.0",
|
|
31
34
|
"sinon": "^11.1.2"
|
|
32
35
|
},
|
|
33
36
|
"license": "MIT"
|