@certik/skynet 0.18.9 → 0.19.1
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 +12 -0
- package/README.md +2 -2
- package/{abi.js → abi.ts} +5 -132
- package/{address.js → address.ts} +4 -4
- package/{api.js → api.ts} +80 -20
- package/{app.js → app.ts} +138 -25
- package/{availability.js → availability.ts} +18 -21
- package/bun.lockb +0 -0
- package/{cli.js → cli.ts} +1 -1
- package/{const.js → const.ts} +42 -3
- package/databricks.ts +82 -0
- package/{date.js → date.ts} +5 -5
- package/{deploy.js → deploy.ts} +157 -44
- package/{dynamodb.js → dynamodb.ts} +159 -186
- package/env.ts +25 -0
- package/eslint.config.mjs +7 -0
- package/examples/{api.js → api.ts} +7 -6
- package/examples/{indexer.js → indexer.ts} +9 -10
- package/examples/{mode-indexer.js → mode-indexer.ts} +18 -10
- package/graphql.ts +43 -0
- package/{indexer.js → indexer.ts} +228 -109
- package/{log.js → log.ts} +6 -6
- package/{opsgenie.js → opsgenie.ts} +29 -6
- package/package.json +17 -11
- package/{s3.js → s3.ts} +29 -19
- package/search.ts +37 -0
- package/selector.ts +72 -0
- package/{slack.js → slack.ts} +19 -12
- package/snowflake.ts +51 -0
- package/tsconfig.json +26 -0
- package/util.ts +35 -0
- package/web3.ts +41 -0
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -20
- package/abi.d.ts +0 -20
- package/address.d.ts +0 -2
- package/api.d.ts +0 -12
- package/app.d.ts +0 -118
- package/availability.d.ts +0 -18
- package/cli.d.ts +0 -4
- package/const.d.ts +0 -42
- package/databricks.js +0 -82
- package/deploy.d.ts +0 -51
- package/dns.d.ts +0 -1
- package/dns.js +0 -27
- package/dynamodb.d.ts +0 -63
- package/env.d.ts +0 -6
- package/env.js +0 -42
- package/examples/consumer.js +0 -30
- package/examples/producer.js +0 -63
- package/graphql.d.ts +0 -3
- package/graphql.js +0 -22
- package/indexer.d.ts +0 -32
- package/log.d.ts +0 -8
- package/opsgenie.d.ts +0 -8
- package/proxy.d.ts +0 -9
- package/proxy.js +0 -154
- package/s3.d.ts +0 -36
- package/search.d.ts +0 -5
- package/search.js +0 -29
- package/selector.d.ts +0 -19
- package/selector.js +0 -71
- package/slack.d.ts +0 -10
- package/snowflake.d.ts +0 -4
- package/snowflake.js +0 -33
- package/sqs.d.ts +0 -3
- package/sqs.js +0 -5
- package/util.d.ts +0 -5
- package/util.js +0 -61
- package/web3.d.ts +0 -25
- package/web3.js +0 -113
|
@@ -8,13 +8,19 @@
|
|
|
8
8
|
// $ examples/mode-indexer deploy --protocol eth
|
|
9
9
|
// $ examples/mode-indexer --help
|
|
10
10
|
|
|
11
|
-
import { modeIndexer, every
|
|
11
|
+
import { modeIndexer, every } from "../app.ts";
|
|
12
12
|
|
|
13
|
-
async function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
async function validate({
|
|
14
|
+
protocol,
|
|
15
|
+
from,
|
|
16
|
+
to,
|
|
17
|
+
verbose,
|
|
18
|
+
}: {
|
|
19
|
+
protocol?: string;
|
|
20
|
+
from?: string;
|
|
21
|
+
to?: string;
|
|
22
|
+
verbose?: boolean;
|
|
23
|
+
}) {
|
|
18
24
|
console.log("validate called with", protocol, from, to, verbose);
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -33,14 +39,16 @@ const app = modeIndexer({
|
|
|
33
39
|
|
|
34
40
|
state: {
|
|
35
41
|
type: "date", // can be omitted, default is block
|
|
36
|
-
getMinId: async () => "2022-09-26"
|
|
37
|
-
getMaxId: async (
|
|
38
|
-
return "2022-10-18";
|
|
42
|
+
getMinId: async () => "2022-09-26" as string,
|
|
43
|
+
getMaxId: async () => {
|
|
44
|
+
return "2022-10-18" as string;
|
|
39
45
|
},
|
|
40
46
|
},
|
|
41
47
|
|
|
42
48
|
build: {
|
|
43
|
-
func:
|
|
49
|
+
func: ({ protocol, from, to, verbose }) => {
|
|
50
|
+
console.log("build called with", protocol, from, to, verbose);
|
|
51
|
+
},
|
|
44
52
|
batchSize: 5,
|
|
45
53
|
concurrency: 2, // default is 1, no concurrency
|
|
46
54
|
|
package/graphql.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type GraphqlVariables = { [key: string]: unknown };
|
|
2
|
+
|
|
3
|
+
type GraphQLError = {
|
|
4
|
+
message: string;
|
|
5
|
+
locations?: { line: number; column: number }[];
|
|
6
|
+
path?: string[];
|
|
7
|
+
extensions?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type GraphQLResponse<TData> = {
|
|
11
|
+
data: TData;
|
|
12
|
+
errors?: GraphQLError[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export async function gql<T>(query: string, variables: GraphqlVariables = {}) {
|
|
16
|
+
const endpoint = process.env["SKYNET_GRAPHQL_ENDPOINT"];
|
|
17
|
+
const apiKey = process.env["SKYNET_GRAPHQL_API_KEY"];
|
|
18
|
+
|
|
19
|
+
if (!endpoint || !apiKey) {
|
|
20
|
+
throw new Error("SKYNET_GRAPHQL_ENDPOINT or SKYNET_GRAPHQL_API_KEY is not set");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const res = await fetch(endpoint, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"x-api-key": apiKey,
|
|
27
|
+
"content-type": "application/json",
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({ query: query.trim(), variables }),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (res.ok) {
|
|
33
|
+
const { data, errors }: GraphQLResponse<T> = await res.json();
|
|
34
|
+
|
|
35
|
+
if (errors && errors.length > 0) {
|
|
36
|
+
throw new Error(JSON.stringify(errors, null, 2));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return data;
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error(await res.text());
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,41 +1,78 @@
|
|
|
1
1
|
import meow from "meow";
|
|
2
|
-
import { createRecord, getRecordByKey } from "./dynamodb.
|
|
3
|
-
import { getEnvironment } from "./env.
|
|
4
|
-
import { exponentialRetry } from "./availability.
|
|
5
|
-
import { range as numberRange, fillRange as fillNumberRange } from "./util.
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { createRecord, getRecordByKey } from "./dynamodb.ts";
|
|
3
|
+
import { getEnvironment } from "./env.ts";
|
|
4
|
+
import { exponentialRetry } from "./availability.ts";
|
|
5
|
+
import { range as numberRange, fillRange as fillNumberRange } from "./util.ts";
|
|
6
|
+
import { getSelectorDesc, getSelectorFlags, toSelectorString } from "./selector.ts";
|
|
7
|
+
import type { SelectorFlags, Selector } from "./selector.ts";
|
|
8
|
+
import { getBinaryName } from "./cli.ts";
|
|
9
|
+
import { inline } from "./log.ts";
|
|
10
|
+
import { findDateAfter, dateRange, daysInRange as fillDateRange } from "./date.ts";
|
|
10
11
|
|
|
11
12
|
const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
type IndexerStateValue = string | number;
|
|
15
|
+
type RebuildStateValue = "init" | "running" | "succeed" | "failed";
|
|
16
|
+
|
|
17
|
+
type StatelessIndexerFlags<TSelector extends Selector> = SelectorFlags<
|
|
18
|
+
TSelector & { verbose: { type: "boolean"; default: false } }
|
|
19
|
+
>;
|
|
20
|
+
type StatelessBuildFunction<TSelector extends Selector> = ({
|
|
21
|
+
verbose,
|
|
22
|
+
...selectorFlags
|
|
23
|
+
}: StatelessIndexerFlags<TSelector>) => Promise<void> | void;
|
|
24
|
+
|
|
25
|
+
type ModeIndexerFlags<TSelector extends Selector> = SelectorFlags<
|
|
26
|
+
TSelector & {
|
|
27
|
+
verbose: { type: "boolean"; default: false };
|
|
28
|
+
mode: { type: "string"; default: "delta" };
|
|
29
|
+
from: { aliases: ["since"]; type: "string" };
|
|
30
|
+
to: { aliases: ["until"]; type: "string" };
|
|
31
|
+
status: { type: "boolean"; default: false };
|
|
20
32
|
}
|
|
33
|
+
>;
|
|
34
|
+
type ModeBuildFunction<T extends IndexerStateValue, TSelector extends Selector> = ({
|
|
35
|
+
from,
|
|
36
|
+
to,
|
|
37
|
+
verbose,
|
|
38
|
+
...selectorFlags
|
|
39
|
+
}: { from: T; to: T; verbose: boolean } & ModeIndexerFlags<TSelector>) => Promise<void | T[]> | void | T[];
|
|
40
|
+
|
|
41
|
+
type ValidateFunction<TSelector extends Selector> = ({
|
|
42
|
+
from,
|
|
43
|
+
to,
|
|
44
|
+
verbose,
|
|
45
|
+
...selectorFlags
|
|
46
|
+
}: ModeIndexerFlags<TSelector>) => Promise<void> | void;
|
|
47
|
+
|
|
48
|
+
type State<T extends IndexerStateValue, TSelector extends Selector> = {
|
|
49
|
+
type: string;
|
|
50
|
+
updateInterval?: () => number;
|
|
51
|
+
getMinId: (selectorFlags: ModeIndexerFlags<TSelector>) => Promise<T>;
|
|
52
|
+
getMaxId: (selectorFlags: ModeIndexerFlags<TSelector>) => Promise<T>;
|
|
53
|
+
};
|
|
21
54
|
|
|
22
|
-
|
|
23
|
-
|
|
55
|
+
type IndexerState<T> = {
|
|
56
|
+
name: string;
|
|
57
|
+
value: T;
|
|
58
|
+
};
|
|
24
59
|
|
|
25
|
-
async function getIndexerLatestId
|
|
26
|
-
|
|
60
|
+
async function getIndexerLatestId<T extends IndexerStateValue, TSelector extends Selector>(
|
|
61
|
+
name: string,
|
|
62
|
+
selectorFlags: ModeIndexerFlags<TSelector>,
|
|
63
|
+
) {
|
|
64
|
+
const record = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
|
|
27
65
|
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
28
66
|
});
|
|
29
67
|
|
|
30
|
-
|
|
31
|
-
return record.value;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return 0;
|
|
68
|
+
return record?.value;
|
|
35
69
|
}
|
|
36
70
|
|
|
37
|
-
async function getIndexerValidatedId
|
|
38
|
-
|
|
71
|
+
async function getIndexerValidatedId<T extends IndexerStateValue, TSelector extends Selector>(
|
|
72
|
+
name: string,
|
|
73
|
+
selectorFlags: ModeIndexerFlags<TSelector>,
|
|
74
|
+
) {
|
|
75
|
+
const record = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
|
|
39
76
|
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
40
77
|
});
|
|
41
78
|
|
|
@@ -43,25 +80,33 @@ async function getIndexerValidatedId(name, selectorFlags) {
|
|
|
43
80
|
return record.value;
|
|
44
81
|
}
|
|
45
82
|
|
|
46
|
-
return
|
|
83
|
+
return undefined;
|
|
47
84
|
}
|
|
48
85
|
|
|
49
|
-
function increaseId(type, currentId, n) {
|
|
86
|
+
function increaseId<T extends IndexerStateValue = IndexerStateValue>(type: string, currentId: T, n: number): T {
|
|
50
87
|
if (type === "date") {
|
|
51
|
-
|
|
88
|
+
if (typeof currentId !== "string") {
|
|
89
|
+
throw new Error("invalid type for date id");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return findDateAfter(currentId, n) as T;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof currentId !== "number") {
|
|
96
|
+
throw new Error("Invalid type for numeric id");
|
|
52
97
|
}
|
|
53
98
|
|
|
54
|
-
return currentId + n;
|
|
99
|
+
return (currentId + n) as T;
|
|
55
100
|
}
|
|
56
101
|
|
|
57
102
|
// for those indexers that can have progress tracked by a numeric state.type
|
|
58
103
|
// such as block height, or timestamp
|
|
59
104
|
// managing state would be helpful to reduce the build time
|
|
60
105
|
// and avoid unnecessary computation & storage
|
|
61
|
-
function createModeIndexerApp({
|
|
106
|
+
function createModeIndexerApp<T extends IndexerStateValue, TSelector extends Selector>({
|
|
62
107
|
binaryName,
|
|
63
108
|
name,
|
|
64
|
-
selector = {},
|
|
109
|
+
selector = {} as TSelector,
|
|
65
110
|
build,
|
|
66
111
|
// number of items run in a batch, determines the { from, to } to the build function
|
|
67
112
|
buildBatchSize = 1,
|
|
@@ -76,48 +121,86 @@ function createModeIndexerApp({
|
|
|
76
121
|
// commit updates every rolling window = validateBatchSize * validateConcurrency
|
|
77
122
|
maxRetry = 2,
|
|
78
123
|
state,
|
|
124
|
+
}: {
|
|
125
|
+
binaryName: string;
|
|
126
|
+
name: string;
|
|
127
|
+
selector: TSelector;
|
|
128
|
+
build: ModeBuildFunction<T, TSelector>;
|
|
129
|
+
maxRetry?: number;
|
|
130
|
+
buildBatchSize?: number;
|
|
131
|
+
buildConcurrency?: number;
|
|
132
|
+
validate?: ValidateFunction<TSelector>;
|
|
133
|
+
validateBatchSize?: number;
|
|
134
|
+
validateConcurrency?: number;
|
|
135
|
+
state: State<T, TSelector>;
|
|
79
136
|
}) {
|
|
80
|
-
const
|
|
137
|
+
const defaultState = {
|
|
81
138
|
type: "block",
|
|
82
139
|
getMinId: async () => 1,
|
|
83
140
|
getMaxId: async () => {
|
|
84
141
|
throw new Error("must implement getMaxId");
|
|
85
142
|
},
|
|
143
|
+
};
|
|
144
|
+
const finalState = {
|
|
145
|
+
...defaultState,
|
|
86
146
|
...state,
|
|
87
147
|
};
|
|
88
148
|
|
|
89
149
|
// type based range functions
|
|
90
|
-
function range(from, to, step) {
|
|
91
|
-
if (
|
|
92
|
-
|
|
150
|
+
function range<T extends IndexerStateValue>(from: T, to: T, step: number) {
|
|
151
|
+
if (typeof from === "string" && typeof to === "string") {
|
|
152
|
+
if (finalState.type === "date") {
|
|
153
|
+
return dateRange(from, to, step) as [T, T][];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
throw new Error("Invalid type for numeric range");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (typeof from === "number" && typeof to === "number") {
|
|
160
|
+
return numberRange(from, to, step) as [T, T][];
|
|
93
161
|
}
|
|
94
162
|
|
|
95
|
-
|
|
163
|
+
throw new Error("Invalid type for range");
|
|
96
164
|
}
|
|
97
165
|
|
|
98
|
-
function fillRange(from, to) {
|
|
99
|
-
if (
|
|
100
|
-
|
|
166
|
+
function fillRange(from: T, to: T) {
|
|
167
|
+
if (typeof from === "string" && typeof to === "string") {
|
|
168
|
+
if (finalState.type === "date") {
|
|
169
|
+
return fillDateRange(from, to) as T[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new Error("Invalid type for numeric range");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (typeof from === "number" && typeof to === "number") {
|
|
176
|
+
return fillNumberRange(from, to) as T[];
|
|
101
177
|
}
|
|
102
178
|
|
|
103
|
-
|
|
179
|
+
throw new Error("Invalid type for range");
|
|
104
180
|
}
|
|
105
181
|
|
|
106
|
-
function offsetRange(from, to) {
|
|
182
|
+
function offsetRange(from: T, to: T) {
|
|
107
183
|
return fillRange(from, to).length;
|
|
108
184
|
}
|
|
109
185
|
|
|
110
|
-
async function runMode(
|
|
186
|
+
async function runMode(flags: ModeIndexerFlags<TSelector>) {
|
|
187
|
+
const { mode, from: fromUntyped, to: toUntyped, status, verbose: verboseUntyped, ...untypeSelectorFlags } = flags;
|
|
188
|
+
|
|
189
|
+
const from = fromUntyped as T;
|
|
190
|
+
const to = toUntyped as T;
|
|
191
|
+
const verbose = verboseUntyped as boolean;
|
|
192
|
+
const selectorFlags = untypeSelectorFlags as ModeIndexerFlags<TSelector>;
|
|
193
|
+
|
|
111
194
|
if (status) {
|
|
112
|
-
const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
195
|
+
const stateItem = await getRecordByKey<IndexerState<RebuildStateValue>>(STATE_TABLE_NAME, {
|
|
113
196
|
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
114
197
|
});
|
|
115
198
|
|
|
116
|
-
const fromItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
199
|
+
const fromItem = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
|
|
117
200
|
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
118
201
|
});
|
|
119
202
|
|
|
120
|
-
const validateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
203
|
+
const validateItem = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
|
|
121
204
|
name: `${name}Validate(${toSelectorString(selectorFlags)})`,
|
|
122
205
|
});
|
|
123
206
|
|
|
@@ -137,22 +220,27 @@ function createModeIndexerApp({
|
|
|
137
220
|
await runReset(selectorFlags);
|
|
138
221
|
await runRebuild(selectorFlags, rebuildFrom, rebuildTo, verbose);
|
|
139
222
|
} else if (mode === "resume-rebuild") {
|
|
140
|
-
const previousRebuildEnds = await getIndexerLatestId
|
|
223
|
+
const previousRebuildEnds = await getIndexerLatestId<T, TSelector>(
|
|
224
|
+
name,
|
|
225
|
+
selectorFlags as ModeIndexerFlags<TSelector>,
|
|
226
|
+
);
|
|
141
227
|
|
|
142
228
|
const rebuildFrom =
|
|
143
|
-
from ||
|
|
229
|
+
from ||
|
|
230
|
+
(previousRebuildEnds !== undefined && increaseId(finalState.type, previousRebuildEnds, 1)) ||
|
|
231
|
+
(await finalState.getMinId(selectorFlags));
|
|
144
232
|
const rebuildTo = to || (await finalState.getMaxId(selectorFlags));
|
|
145
233
|
|
|
146
234
|
await runRebuild(selectorFlags, rebuildFrom, rebuildTo, verbose);
|
|
147
235
|
} else if (mode === "validate" || mode === "validation") {
|
|
148
|
-
const previousRebuildEnds = await getIndexerLatestId(name, selectorFlags);
|
|
236
|
+
const previousRebuildEnds = await getIndexerLatestId<T, TSelector>(name, selectorFlags);
|
|
149
237
|
|
|
150
238
|
if (!previousRebuildEnds) {
|
|
151
239
|
inline.log(`[MODE INDEXER] cannot validate without a successful rebuild`);
|
|
152
240
|
process.exit(0);
|
|
153
241
|
}
|
|
154
242
|
|
|
155
|
-
const previousValidatedTo = await getIndexerValidatedId(name, selectorFlags);
|
|
243
|
+
const previousValidatedTo = await getIndexerValidatedId<T, TSelector>(name, selectorFlags);
|
|
156
244
|
|
|
157
245
|
const validateFrom = from || previousValidatedTo || (await finalState.getMinId(selectorFlags));
|
|
158
246
|
const validateTo = to || previousRebuildEnds;
|
|
@@ -177,7 +265,7 @@ function createModeIndexerApp({
|
|
|
177
265
|
|
|
178
266
|
await runRange(selectorFlags, from, to, verbose);
|
|
179
267
|
} else {
|
|
180
|
-
const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
|
|
268
|
+
const stateItem = await getRecordByKey<IndexerState<string>>(STATE_TABLE_NAME, {
|
|
181
269
|
name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
|
|
182
270
|
});
|
|
183
271
|
|
|
@@ -187,14 +275,20 @@ function createModeIndexerApp({
|
|
|
187
275
|
process.exit(0);
|
|
188
276
|
}
|
|
189
277
|
|
|
190
|
-
const
|
|
278
|
+
const latestId = await getIndexerLatestId<T, TSelector>(name, selectorFlags);
|
|
279
|
+
|
|
280
|
+
if (!latestId) {
|
|
281
|
+
throw new Error(`[MODE INDEXER] cannot find the latest ${finalState.type}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const deltaFrom = increaseId(finalState.type, latestId, 1);
|
|
191
285
|
const deltaTo = await state.getMaxId(selectorFlags);
|
|
192
286
|
|
|
193
287
|
await runDelta(selectorFlags, deltaFrom, deltaTo, verbose);
|
|
194
288
|
}
|
|
195
289
|
}
|
|
196
290
|
|
|
197
|
-
async function runRange(selectorFlags
|
|
291
|
+
async function runRange(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
|
|
198
292
|
const startTime = Date.now();
|
|
199
293
|
|
|
200
294
|
inline.log(
|
|
@@ -215,7 +309,13 @@ function createModeIndexerApp({
|
|
|
215
309
|
}
|
|
216
310
|
}
|
|
217
311
|
|
|
218
|
-
async function runValidate(
|
|
312
|
+
async function runValidate(
|
|
313
|
+
selectorFlags: ModeIndexerFlags<TSelector>,
|
|
314
|
+
from: T,
|
|
315
|
+
to: T,
|
|
316
|
+
shouldSaveState?: boolean,
|
|
317
|
+
verbose?: boolean,
|
|
318
|
+
) {
|
|
219
319
|
if (!validate) {
|
|
220
320
|
inline.log(`[MODE INDEXER] the indexer doesn't support validate mode, validate function not implemented`);
|
|
221
321
|
process.exit(1);
|
|
@@ -236,7 +336,7 @@ function createModeIndexerApp({
|
|
|
236
336
|
`[MODE INDEXER] from=${from}, to=${to}, batchSize=${validateBatchSize}, concurrency=${validateConcurrency}`,
|
|
237
337
|
);
|
|
238
338
|
|
|
239
|
-
for (
|
|
339
|
+
for (const [windowStart, windowEnd] of windows) {
|
|
240
340
|
inline.log(`[MODE INDEXER] validating window ${windowStart}~${windowEnd}, concurrency=${validateConcurrency}`);
|
|
241
341
|
|
|
242
342
|
const batches = range(windowStart, windowEnd, validateBatchSize);
|
|
@@ -291,47 +391,54 @@ function createModeIndexerApp({
|
|
|
291
391
|
);
|
|
292
392
|
}
|
|
293
393
|
|
|
294
|
-
async function execBuild(
|
|
295
|
-
|
|
394
|
+
async function execBuild(
|
|
395
|
+
selectorFlags: ModeIndexerFlags<TSelector>,
|
|
396
|
+
from: T,
|
|
397
|
+
to: T,
|
|
398
|
+
verbose: boolean,
|
|
399
|
+
shouldSaveState = false,
|
|
400
|
+
) {
|
|
401
|
+
let failedIds: T[] = [];
|
|
296
402
|
|
|
297
403
|
const windows = range(from, to, buildBatchSize * buildConcurrency);
|
|
298
404
|
|
|
299
|
-
for (
|
|
405
|
+
for (const [windowStart, windowEnd] of windows) {
|
|
300
406
|
inline.log(`[MODE INDEXER] building window ${windowStart}~${windowEnd}, concurrency = ${buildConcurrency}`);
|
|
301
407
|
|
|
302
408
|
const batches = range(windowStart, windowEnd, buildBatchSize);
|
|
303
409
|
|
|
304
410
|
// add a retry for errors
|
|
305
411
|
const batchResults = await Promise.all(
|
|
306
|
-
batches.map(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
412
|
+
batches.map(
|
|
413
|
+
async ([batchStart, batchEnd]) =>
|
|
414
|
+
await exponentialRetry(
|
|
415
|
+
async () => {
|
|
416
|
+
try {
|
|
417
|
+
const ids = await build({
|
|
418
|
+
...selectorFlags,
|
|
419
|
+
from: batchStart,
|
|
420
|
+
to: batchEnd,
|
|
421
|
+
verbose,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
if (ids && ids.length > 0) {
|
|
425
|
+
return ids;
|
|
426
|
+
} else {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
} catch (err) {
|
|
430
|
+
inline.error(`[MODE INDEXER] got error in build`, err);
|
|
431
|
+
|
|
432
|
+
return fillRange(batchStart, batchEnd);
|
|
321
433
|
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
test: (r) => !r,
|
|
331
|
-
verbose,
|
|
332
|
-
},
|
|
333
|
-
);
|
|
334
|
-
}),
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
maxRetry,
|
|
437
|
+
test: (r) => !r,
|
|
438
|
+
verbose,
|
|
439
|
+
},
|
|
440
|
+
),
|
|
441
|
+
),
|
|
335
442
|
);
|
|
336
443
|
|
|
337
444
|
if (shouldSaveState) {
|
|
@@ -357,7 +464,7 @@ function createModeIndexerApp({
|
|
|
357
464
|
return failedIds;
|
|
358
465
|
}
|
|
359
466
|
|
|
360
|
-
async function runRebuild(selectorFlags
|
|
467
|
+
async function runRebuild(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
|
|
361
468
|
const startTime = Date.now();
|
|
362
469
|
|
|
363
470
|
inline.log(
|
|
@@ -403,7 +510,7 @@ function createModeIndexerApp({
|
|
|
403
510
|
}
|
|
404
511
|
}
|
|
405
512
|
|
|
406
|
-
async function runDelta(selectorFlags
|
|
513
|
+
async function runDelta(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
|
|
407
514
|
const startTime = Date.now();
|
|
408
515
|
|
|
409
516
|
if (to < from) {
|
|
@@ -437,7 +544,7 @@ function createModeIndexerApp({
|
|
|
437
544
|
|
|
438
545
|
await createRecord(STATE_TABLE_NAME, {
|
|
439
546
|
name: `${name}Since(${toSelectorString(selectorFlags)})`,
|
|
440
|
-
value:
|
|
547
|
+
value: to < failedIds[0] ? to : failedIds[0],
|
|
441
548
|
});
|
|
442
549
|
|
|
443
550
|
process.exit(1);
|
|
@@ -462,7 +569,7 @@ function createModeIndexerApp({
|
|
|
462
569
|
}
|
|
463
570
|
}
|
|
464
571
|
|
|
465
|
-
async function runReset(selectorFlags) {
|
|
572
|
+
async function runReset(selectorFlags: ModeIndexerFlags<TSelector>) {
|
|
466
573
|
const startTime = Date.now();
|
|
467
574
|
|
|
468
575
|
inline.log(`[MODE INDEXER] starting reset, ${toSelectorString(selectorFlags, ", ")}`);
|
|
@@ -486,7 +593,7 @@ function createModeIndexerApp({
|
|
|
486
593
|
inline.log(`[MODE INDEXER] reset successfully in ${Date.now() - startTime}ms`);
|
|
487
594
|
}
|
|
488
595
|
|
|
489
|
-
function run() {
|
|
596
|
+
async function run() {
|
|
490
597
|
if (!binaryName) {
|
|
491
598
|
binaryName = getBinaryName();
|
|
492
599
|
}
|
|
@@ -498,7 +605,7 @@ function createModeIndexerApp({
|
|
|
498
605
|
$ ${binaryName} <options>
|
|
499
606
|
|
|
500
607
|
Options
|
|
501
|
-
${getSelectorDesc(selector)}
|
|
608
|
+
${selector ? getSelectorDesc(selector) : ""}
|
|
502
609
|
--mode could be delta/rebuild/resume-rebuild/validate/one/range/reset
|
|
503
610
|
--from min ${finalState.type} to build
|
|
504
611
|
--to max ${finalState.type} to build
|
|
@@ -535,20 +642,32 @@ ${getSelectorDesc(selector)}
|
|
|
535
642
|
},
|
|
536
643
|
);
|
|
537
644
|
|
|
538
|
-
|
|
645
|
+
try {
|
|
646
|
+
return runMode(cli.flags);
|
|
647
|
+
} catch (err) {
|
|
539
648
|
inline.error(err);
|
|
540
649
|
process.exit(1);
|
|
541
|
-
}
|
|
650
|
+
}
|
|
542
651
|
}
|
|
543
652
|
|
|
544
653
|
return { run };
|
|
545
654
|
}
|
|
546
655
|
|
|
547
|
-
// for
|
|
656
|
+
// for indexers that don't rely on a cursor
|
|
548
657
|
// e.g. should always rebuild everything from scratch
|
|
549
658
|
// or that the state can be easily inferred from existing data
|
|
550
|
-
function createIndexerApp
|
|
551
|
-
|
|
659
|
+
function createIndexerApp<TSelector extends Selector>({
|
|
660
|
+
binaryName,
|
|
661
|
+
selector = {} as TSelector,
|
|
662
|
+
build,
|
|
663
|
+
maxRetry = 2,
|
|
664
|
+
}: {
|
|
665
|
+
binaryName: string;
|
|
666
|
+
selector?: TSelector;
|
|
667
|
+
build: StatelessBuildFunction<TSelector>;
|
|
668
|
+
maxRetry?: number;
|
|
669
|
+
}) {
|
|
670
|
+
async function run() {
|
|
552
671
|
if (!binaryName) {
|
|
553
672
|
binaryName = getBinaryName();
|
|
554
673
|
}
|
|
@@ -559,7 +678,7 @@ function createIndexerApp({ binaryName, selector = {}, build, maxRetry = 2 }) {
|
|
|
559
678
|
$ ${binaryName} <options>
|
|
560
679
|
|
|
561
680
|
Options
|
|
562
|
-
${getSelectorDesc(selector)}
|
|
681
|
+
${selector ? getSelectorDesc(selector) : ""}
|
|
563
682
|
--verbose Output debug messages
|
|
564
683
|
`,
|
|
565
684
|
{
|
|
@@ -576,7 +695,12 @@ ${getSelectorDesc(selector)}
|
|
|
576
695
|
},
|
|
577
696
|
);
|
|
578
697
|
|
|
579
|
-
async function runBuild(
|
|
698
|
+
async function runBuild(flags: StatelessIndexerFlags<TSelector>) {
|
|
699
|
+
const { verbose: untypedVerbose, ...untypedSelectorFlags } = flags;
|
|
700
|
+
|
|
701
|
+
const verbose = untypedVerbose as boolean;
|
|
702
|
+
const selectorFlags = untypedSelectorFlags as StatelessIndexerFlags<TSelector>;
|
|
703
|
+
|
|
580
704
|
const startTime = Date.now();
|
|
581
705
|
|
|
582
706
|
if (Object.keys(selectorFlags).length > 0) {
|
|
@@ -588,7 +712,7 @@ ${getSelectorDesc(selector)}
|
|
|
588
712
|
const result = await exponentialRetry(
|
|
589
713
|
async () => {
|
|
590
714
|
try {
|
|
591
|
-
await build(
|
|
715
|
+
await build(flags);
|
|
592
716
|
|
|
593
717
|
return true;
|
|
594
718
|
} catch (err) {
|
|
@@ -600,7 +724,7 @@ ${getSelectorDesc(selector)}
|
|
|
600
724
|
{
|
|
601
725
|
maxRetry,
|
|
602
726
|
test: (r) => r,
|
|
603
|
-
verbose,
|
|
727
|
+
verbose: verbose as boolean,
|
|
604
728
|
},
|
|
605
729
|
);
|
|
606
730
|
|
|
@@ -620,11 +744,6 @@ ${getSelectorDesc(selector)}
|
|
|
620
744
|
return { run };
|
|
621
745
|
}
|
|
622
746
|
|
|
623
|
-
export {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
createIndexerApp,
|
|
627
|
-
getIndexerState,
|
|
628
|
-
getIndexerLatestId,
|
|
629
|
-
getIndexerValidatedId,
|
|
630
|
-
};
|
|
747
|
+
export { increaseId, createModeIndexerApp, createIndexerApp };
|
|
748
|
+
|
|
749
|
+
export type { IndexerStateValue, State, StatelessBuildFunction, ModeBuildFunction, ValidateFunction };
|
package/{log.js → log.ts}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
function isObject(a) {
|
|
1
|
+
function isObject(a: unknown): a is Record<string, unknown> {
|
|
2
2
|
return !!a && a.constructor === Object;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
function print(o) {
|
|
5
|
+
function print(o: unknown): string {
|
|
6
6
|
if (Array.isArray(o)) {
|
|
7
7
|
return `[${o.map(print).join(", ")}]`;
|
|
8
8
|
}
|
|
@@ -16,7 +16,7 @@ function print(o) {
|
|
|
16
16
|
return `${o}`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function getLine(params) {
|
|
19
|
+
function getLine(params: unknown[]) {
|
|
20
20
|
let line = "";
|
|
21
21
|
|
|
22
22
|
// Convert to string and filter out newline to tabs (AWS Athena)
|
|
@@ -34,12 +34,12 @@ function timestamp() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const inline = {
|
|
37
|
-
log: function (...args) {
|
|
37
|
+
log: function (...args: unknown[]) {
|
|
38
38
|
console.log(`${timestamp()} ${getLine(args)}`);
|
|
39
39
|
},
|
|
40
|
-
error: function (...args) {
|
|
40
|
+
error: function (...args: unknown[]) {
|
|
41
41
|
console.error(`${timestamp()} ${getLine(args)}`);
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
export {
|
|
45
|
+
export { print, getLine, inline };
|