@certik/skynet 0.7.20 → 0.8.0

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/examples/indexer CHANGED
@@ -2,24 +2,55 @@
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/indexer --protocol bsc --verbose
6
- // $ examples/indexer --protocol eth
5
+ // $ examples/indexer run --protocol bsc --verbose
6
+ // $ examples/indexer run --protocol eth
7
+ // $ examples/indexer check --protocol eth
8
+ // $ examples/indexer deploy --protocol eth
7
9
  // $ examples/indexer --help
8
10
 
9
- const { createIndexerApp } = require("../indexer");
11
+ const { indexer, ERROR_LEVEL } = require("../app");
10
12
 
11
13
  async function build({ protocol, verbose }) {
12
14
  console.log("build called with", protocol, verbose);
13
15
 
14
16
  if (protocol === "eth") {
15
- throw new Error("when problem is not recoverable and cannot be resolved by retry, throw error here");
17
+ throw new Error("use eth to test error handling");
16
18
  }
17
19
  }
18
20
 
19
- const { run } = createIndexerApp({
20
- name: "ShareJSTestIndexer",
21
+ async function check({ protocol, state, verbose }) {
22
+ console.log("check called with", protocol, state, verbose);
23
+
24
+ // latestId
25
+ // latestIdOnChain
26
+
27
+ const errors = [];
28
+
29
+ errors.push({
30
+ type: ERROR_LEVEL.WARNING,
31
+ message: "processed *height* lagged behind", // can be markdown
32
+ });
33
+
34
+ return errors;
35
+ }
36
+
37
+ const app = indexer({
38
+ name: "LibSkynetExampleIndexer",
21
39
  selector: { protocol: { type: "string" } },
22
- build
40
+
41
+ build: {
42
+ func: build,
43
+ schedule: "@minutely",
44
+ cpu: 600,
45
+ mem: 200,
46
+ },
47
+
48
+ check: {
49
+ func: check,
50
+ schedule: "@minutely",
51
+ maxRetry: 0,
52
+ slackChannel: "skynet-notifications-local-dev",
53
+ },
23
54
  });
24
55
 
25
- run();
56
+ app();
@@ -7,8 +7,8 @@
7
7
  const { createDeploy } = require("../deploy");
8
8
 
9
9
  const { deploy } = createDeploy({
10
- name: "shared-js-test-consumer",
11
- workingDirectory: "shared-js",
10
+ name: "lib-skynet-test-consumer",
11
+ workingDirectory: "lib-skynet",
12
12
  bin: "examples/kafka-consumer",
13
13
  selector: { protocol: { type: "string" } },
14
14
  env: {
@@ -7,12 +7,13 @@
7
7
  const { createDeploy } = require("../deploy");
8
8
 
9
9
  const { deploy } = createDeploy({
10
- name: "ShareJSTestIndexer",
11
- workingDirectory: "shared-js",
10
+ name: "lib-skynet-test-indexer",
11
+ workingDirectory: "lib-skynet",
12
12
  bin: "examples/indexer",
13
13
  selector: { protocol: { type: "string" } },
14
+ schedule: "@minutely",
14
15
  cpu: 600,
15
- mem: 200
16
+ mem: 200,
16
17
  });
17
18
 
18
19
  deploy();
@@ -7,8 +7,8 @@
7
7
  const { createModeDeploy } = require("../deploy");
8
8
 
9
9
  const { deploy } = createModeDeploy({
10
- name: "ShareJSTestModeIndexer",
11
- workingDirectory: "shared-js",
10
+ name: "lib-skynet-test-mode-indexer",
11
+ workingDirectory: "lib-skynet",
12
12
  bin: "examples/mode-indexer",
13
13
  selector: { protocol: { type: "string" } },
14
14
  deltaSchedule: "@minutely",
@@ -9,8 +9,8 @@ const path = require("path");
9
9
  const { createDeploy } = require("../deploy");
10
10
 
11
11
  const { deploy } = createDeploy({
12
- name: "shared-js-test-producer",
13
- workingDirectory: "shared-js", // where package.json was located
12
+ name: "lib-skynet-test-producer",
13
+ workingDirectory: "lib-skynet", // where package.json was located
14
14
  bin: "examples/kafka-producer",
15
15
  selector: { protocol: { type: "string" } },
16
16
  env: {
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ // this file is executable and is for kafka producer testing
4
+ // a few test commands to try on
5
+ // $ examples/indexer --protocol bsc --verbose
6
+ // $ examples/indexer --protocol eth
7
+ // $ examples/indexer --help
8
+
9
+ const { createIndexerApp } = require("../indexer");
10
+
11
+ async function build({ protocol, verbose }) {
12
+ console.log("build called with", protocol, verbose);
13
+
14
+ if (protocol === "eth") {
15
+ throw new Error("when problem is not recoverable and cannot be resolved by retry, throw error here");
16
+ }
17
+ }
18
+
19
+ const { run } = createIndexerApp({
20
+ name: "lib-skynet-test-indexer",
21
+ selector: { protocol: { type: "string" } },
22
+ build
23
+ });
24
+
25
+ run();
@@ -24,7 +24,7 @@ const { run } = createConsumerApp({
24
24
  selector: { protocol: { type: "string" } },
25
25
 
26
26
  consumer: {
27
- topic: ({ protocol }) => `shared-js-test-kafka-${protocol}-dev`,
27
+ topic: ({ protocol }) => `lib-skynet-test-kafka-${protocol}-dev`,
28
28
  consume,
29
29
  maxRetry: 1 // default to 2
30
30
  }
@@ -42,8 +42,8 @@ const { run } = createProducerApp({
42
42
  selector: { protocol: { type: "string" } },
43
43
 
44
44
  producer: {
45
- topic: ({ protocol }) => `shared-js-test-kafka-${protocol}-dev`,
46
- deadLetterTopic: ({ protocol }) => `shared-js-test-kafka-${protocol}-dead-letter-dev`, // problematic ids will be sent to dead letter topic for later retry
45
+ topic: ({ protocol }) => `lib-skynet-test-kafka-${protocol}-dev`,
46
+ deadLetterTopic: ({ protocol }) => `lib-skynet-test-kafka-${protocol}-dead-letter-dev`, // problematic ids will be sent to dead letter topic for later retry
47
47
  produce,
48
48
  batchSize: 10, // default to 50
49
49
  maxRetry: 1 // default to 2
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+
3
+ // this file is executable and is for kafka producer testing
4
+ // a few test commands to try on
5
+ // $ examples/indexer --protocol bsc --verbose
6
+ // $ examples/indexer --help
7
+
8
+ const { createModeIndexerApp } = require("../indexer");
9
+ const { readFile, writeFile } = require("fs/promises");
10
+
11
+ async function build({ protocol, from, to, verbose }) {
12
+ console.log("build called with", protocol, from, to, verbose);
13
+
14
+ for (let i = from; i <= to; i++) {
15
+ if (i !== 5) {
16
+ // simulate a gap, id = 5
17
+ // we can use validate mode to fix
18
+ const filename = `/tmp/ShareJSTestModeIndexer-${protocol}-${i}`;
19
+
20
+ await writeFile(filename, "helloworld");
21
+ }
22
+ }
23
+
24
+ console.log("build done", protocol, from, to);
25
+ }
26
+
27
+ async function validate({ protocol, from, to, verbose }) {
28
+ console.log("validate called with", protocol, from, to, verbose);
29
+
30
+ for (let i = from; i <= to; i++) {
31
+ const filename = `/tmp/ShareJSTestModeIndexer-${protocol}-${i}`;
32
+
33
+ try {
34
+ await readFile(filename);
35
+ } catch (notFound) {
36
+ // fix missing data
37
+ await writeFile(filename, "helloworld");
38
+ }
39
+ }
40
+
41
+ console.log("validate done", protocol, from, to);
42
+ }
43
+
44
+ const { run } = createModeIndexerApp({
45
+ name: "ShareJSTestModeIndexer",
46
+ selector: { protocol: { type: "string" } },
47
+
48
+ build,
49
+ buildBatchSize: 5,
50
+ buildConcurrency: 2, // default is 1, no concurrency
51
+ validate,
52
+ validateBatchSize: 2,
53
+ validateConcurrency: 2, // default is 1, no concurrency
54
+
55
+ state: {
56
+ type: "block", // can be omitted, default is block
57
+ getMinId: async () => 2, // default returns 1
58
+ getMaxId: async ({ protocol }) => {
59
+ return 10;
60
+ }
61
+ }
62
+ });
63
+
64
+ run();
@@ -2,63 +2,76 @@
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/indexer --protocol bsc --verbose
6
- // $ examples/indexer --help
5
+ // $ examples/mode-indexer run --protocol bsc --verbose
6
+ // $ examples/mode-indexer run --mode rebuild --protocol bsc --verbose
7
+ // $ examples/mode-indexer run --protocol eth
8
+ // $ examples/mode-indexer check --protocol eth
9
+ // $ examples/mode-indexer deploy --protocol eth
10
+ // $ examples/mode-indexer --help
7
11
 
8
- const { createModeIndexerApp } = require("../indexer");
9
- const { readFile, writeFile } = require("fs/promises");
12
+ const { modeIndexer } = require("../app");
10
13
 
11
14
  async function build({ protocol, from, to, verbose }) {
12
15
  console.log("build called with", protocol, from, to, verbose);
13
-
14
- for (let i = from; i <= to; i++) {
15
- if (i !== 5) {
16
- // simulate a gap, id = 5
17
- // we can use validate mode to fix
18
- const filename = `/tmp/ShareJSTestModeIndexer-${protocol}-${i}`;
19
-
20
- await writeFile(filename, "helloworld");
21
- }
22
- }
23
-
24
- console.log("build done", protocol, from, to);
25
16
  }
26
17
 
27
18
  async function validate({ protocol, from, to, verbose }) {
28
19
  console.log("validate called with", protocol, from, to, verbose);
20
+ }
21
+
22
+ async function check({ mode, protocol, state, verbose }) {
23
+ console.log("check called with", mode, protocol, state, verbose);
29
24
 
30
- for (let i = from; i <= to; i++) {
31
- const filename = `/tmp/ShareJSTestModeIndexer-${protocol}-${i}`;
25
+ const errors = [];
32
26
 
33
- try {
34
- await readFile(filename);
35
- } catch (notFound) {
36
- // fix missing data
37
- await writeFile(filename, "helloworld");
38
- }
39
- }
27
+ // if (state.latestId < getBlockLatestHeight(protocol)) {
28
+ // errors.push({ type: ERROR_LEVEL.INFO, message: "processed height lagged behind" });
29
+ // }
40
30
 
41
- console.log("validate done", protocol, from, to);
31
+ return errors;
42
32
  }
43
33
 
44
- const { run } = createModeIndexerApp({
45
- name: "ShareJSTestModeIndexer",
34
+ const app = modeIndexer({
35
+ name: "LibSkynetExampleModeIndexer",
46
36
  selector: { protocol: { type: "string" } },
47
37
 
48
- build,
49
- buildBatchSize: 5,
50
- buildConcurrency: 2, // default is 1, no concurrency
51
- validate,
52
- validateBatchSize: 2,
53
- validateConcurrency: 2, // default is 1, no concurrency
54
-
55
38
  state: {
56
39
  type: "block", // can be omitted, default is block
57
40
  getMinId: async () => 2, // default returns 1
58
41
  getMaxId: async ({ protocol }) => {
59
42
  return 10;
60
- }
61
- }
43
+ },
44
+ },
45
+
46
+ env: {
47
+ SKYNET_SLACK_TOKEN: SENSITIVE_VALUE,
48
+ },
49
+
50
+ build: {
51
+ func: build,
52
+ batchSize: 5,
53
+ concurrency: 2, // default is 1, no concurrency
54
+
55
+ schedule: "@minutely",
56
+ cpu: 800,
57
+ mem: 400,
58
+ },
59
+
60
+ validate: {
61
+ func: validate,
62
+ batchSize: 2,
63
+ concurrency: 2, // default is 1, no concurrency
64
+
65
+ schedule: "@hourly",
66
+ cpu: 600,
67
+ mem: 200,
68
+ },
69
+
70
+ check: {
71
+ func: check,
72
+ schedule: "@minutely",
73
+ slackChannel: "skynet-notifications-local-dev",
74
+ },
62
75
  });
63
76
 
64
- run();
77
+ app();
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ // this file is executable and is for kafka producer testing
4
+ // a few test commands to try on
5
+ // $ examples/producer run --protocol bsc --verbose
6
+ // $ examples/producer run --protocol eth
7
+ // $ examples/producer check --protocol eth
8
+ // $ examples/producer deploy --protocol eth
9
+ // $ examples/producer --help
10
+
11
+ const { producer, SENSITIVE_VALUE, ERROR_LEVEL } = require("../app");
12
+
13
+ async function produce({ protocol, from, to, verbose, send }) {
14
+ console.log("produce called with", protocol, from, to, verbose);
15
+ }
16
+
17
+ async function check({ protocol, state, verbose }) {
18
+ console.log("check called with", protocol, state, verbose);
19
+
20
+ const errors = [];
21
+
22
+ errors.push({ type: ERROR_LEVEL.CRITICAL, message: "producer error" });
23
+
24
+ return errors;
25
+ }
26
+
27
+ const app = producer({
28
+ name: "LibSkynetExampleProducer",
29
+ selector: { protocol: { type: "string" } },
30
+
31
+ state: {
32
+ type: "block", // can be omitted, default is block
33
+ updateInterval: ({ protocol }) => (protocol === "bsc" ? 3000 : 20000), // how often max id is increasing, will determine poll interval, default to 5000ms
34
+ getMinId: async () => 4, // default returns 1
35
+ getMaxId: async ({ protocol }) => {
36
+ console.log("getMaxId called", protocol);
37
+
38
+ return 100;
39
+ },
40
+ },
41
+
42
+ env: {
43
+ SKYNET_KAFKA_SERVER: SENSITIVE_VALUE,
44
+ SKYNET_KAFKA_USERNAME: SENSITIVE_VALUE,
45
+ SKYNET_KAFKA_PASSWORD: SENSITIVE_VALUE,
46
+ },
47
+
48
+ produce: {
49
+ func: produce,
50
+
51
+ topic: ({ protocol }) => `lib-skynet-test-kafka-${protocol}-dev`,
52
+ deadLetterTopic: ({ protocol }) => `lib-skynet-test-kafka-${protocol}-dead-letter-dev`, // problematic ids will be sent to dead letter topic for later retry
53
+
54
+ batchSize: 10, // default 50
55
+ maxRetry: 1, // default 2
56
+
57
+ cpu: 600,
58
+ mem: 200,
59
+ },
60
+
61
+ check: {
62
+ func: check,
63
+ schedule: "@minutely",
64
+ slackChannel: "skynet-notifications-local-dev",
65
+ },
66
+ });
67
+
68
+ app();
package/indexer.js CHANGED
@@ -1,10 +1,10 @@
1
- const path = require("path");
2
1
  const meow = require("meow");
3
2
  const { createRecord, getRecordByKey } = require("./dynamodb");
4
3
  const { getEnvironment } = require("./env");
5
4
  const { exponentialRetry } = require("./availability");
6
5
  const { range, fillRange } = require("./util");
7
6
  const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
7
+ const { getBinaryName } = require("./cli");
8
8
 
9
9
  const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
10
10
 
@@ -49,6 +49,7 @@ async function getIndexerValidatedId(name, selectorFlags) {
49
49
  // managing state would be helpful to reduce the build time
50
50
  // and avoid unnecessary computation & storage
51
51
  function createModeIndexerApp({
52
+ binaryName,
52
53
  name,
53
54
  selector = {},
54
55
  build,
@@ -447,8 +448,9 @@ function createModeIndexerApp({
447
448
  }
448
449
 
449
450
  function run() {
450
- const binaryNameParts = process.argv[1].split(path.sep);
451
- const binaryName = binaryNameParts[binaryNameParts.length - 1];
451
+ if (!binaryName) {
452
+ binaryName = getBinaryName();
453
+ }
452
454
 
453
455
  const cli = meow(
454
456
  `
@@ -506,10 +508,11 @@ ${getSelectorDesc(selector)}
506
508
  // for those indexers that does not rely on a curosr
507
509
  // e.g. should always rebuild everything from scratch
508
510
  // or that the state can be easily inferred from existing data
509
- function createIndexerApp({ name, selector = {}, build, maxRetry = 2 }) {
511
+ function createIndexerApp({ binaryName, name, selector = {}, build, maxRetry = 2 }) {
510
512
  function run() {
511
- const binaryNameParts = process.argv[1].split(path.sep);
512
- const binaryName = binaryNameParts[binaryNameParts.length - 1];
513
+ if (!binaryName) {
514
+ binaryName = getBinaryName();
515
+ }
513
516
 
514
517
  const cli = meow(
515
518
  `
@@ -565,7 +568,7 @@ ${getSelectorDesc(selector)}
565
568
  value: new Date().toISOString(),
566
569
  });
567
570
 
568
- console.log(`[INDEXER] reset successfully in ${Date.now() - startTime}ms`);
571
+ console.log(`[INDEXER] build successfully in ${Date.now() - startTime}ms`);
569
572
  }
570
573
 
571
574
  runBuild(cli.flags).catch((err) => {
package/kafka.js CHANGED
@@ -1,4 +1,3 @@
1
- const path = require("path");
2
1
  const meow = require("meow");
3
2
  const { getEnvironment, getEnvOrThrow } = require("./env");
4
3
  const { wait } = require("./availability");
@@ -6,6 +5,7 @@ const { Kafka, logLevel } = require("kafkajs");
6
5
  const { getSelectorFlags, getSelectorDesc, toSelectorString } = require("./selector");
7
6
  const { createRecord, getRecordByKey, deleteRecordsByHashKey } = require("./dynamodb");
8
7
  const { exponentialRetry } = require("./availability");
8
+ const { getBinaryName } = require("./cli");
9
9
 
10
10
  const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
11
11
 
@@ -137,10 +137,11 @@ async function consumeMessages(consumerId, topic, callback) {
137
137
  return stopConsumeMessages;
138
138
  }
139
139
 
140
- function createProducerApp({ name, selector = {}, producer, state }) {
140
+ function createProducerApp({ binaryName, name, selector = {}, producer, state }) {
141
141
  function run() {
142
- const binaryNameParts = process.argv[1].split(path.sep);
143
- const binaryName = binaryNameParts[binaryNameParts.length - 1];
142
+ if (!binaryName) {
143
+ binaryName = getBinaryName();
144
+ }
144
145
 
145
146
  const finalState = {
146
147
  type: "block",
@@ -337,10 +338,11 @@ ${getSelectorDesc(selector)}
337
338
  return { run };
338
339
  }
339
340
 
340
- function createConsumerApp({ name, selector = {}, consumer }) {
341
+ function createConsumerApp({ binaryName, name, selector = {}, consumer }) {
341
342
  function run() {
342
- const binaryNameParts = process.argv[1].split(path.sep);
343
- const binaryName = binaryNameParts[binaryNameParts.length - 1];
343
+ if (!binaryName) {
344
+ binaryName = getBinaryName();
345
+ }
344
346
 
345
347
  const cli = meow(
346
348
  `