@sentio/runtime 2.62.0-rc.3 → 2.62.0-rc.5
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/lib/{chunk-ID7RUJZE.js → chunk-I5YHR3CE.js} +91 -650
- package/lib/chunk-I5YHR3CE.js.map +1 -0
- package/lib/{chunk-BUEDBCDW.js → chunk-RPV67F56.js} +44 -14
- package/lib/{chunk-BUEDBCDW.js.map → chunk-RPV67F56.js.map} +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/{processor-DwZlMkFj.d.ts → processor-HNY62jHs.d.ts} +7 -23
- package/lib/processor-runner.d.ts +0 -33
- package/lib/processor-runner.js +4163 -1423
- package/lib/processor-runner.js.map +1 -1
- package/lib/service-worker.js +2 -2
- package/lib/test-processor.test.d.ts +1 -1
- package/package.json +1 -3
- package/src/gen/processor/protos/processor.ts +59 -356
- package/src/gen/service/common/protos/common.ts +6 -0
- package/src/processor-runner.ts +185 -161
- package/src/service-manager.ts +2 -1
- package/lib/chunk-ID7RUJZE.js.map +0 -1
package/src/processor-runner.ts
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
import fs from 'fs-extra'
|
4
4
|
|
5
5
|
import { compressionAlgorithms } from '@grpc/grpc-js'
|
6
|
-
import
|
6
|
+
import { Command, InvalidArgumentError } from 'commander'
|
7
7
|
import { createServer } from 'nice-grpc'
|
8
8
|
import { errorDetailsServerMiddleware } from 'nice-grpc-error-details'
|
9
9
|
// import { registry as niceGrpcRegistry } from 'nice-grpc-prometheus'
|
@@ -33,189 +33,213 @@ try {
|
|
33
33
|
} catch (e) {
|
34
34
|
console.error('Failed to parse worker number', e)
|
35
35
|
}
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
{
|
43
|
-
name: 'chains-config',
|
44
|
-
alias: 'c',
|
45
|
-
type: String,
|
46
|
-
defaultValue: 'chains-config.json'
|
47
|
-
},
|
48
|
-
{ name: 'chainquery-server', type: String, defaultValue: '' },
|
49
|
-
{ name: 'pricefeed-server', type: String, defaultValue: '' },
|
50
|
-
{ name: 'log-format', type: String, defaultValue: 'console' },
|
51
|
-
{ name: 'debug', type: Boolean, defaultValue: false },
|
52
|
-
{ name: 'otlp-debug', type: Boolean, defaultValue: false },
|
53
|
-
{ name: 'start-action-server', type: Boolean, defaultValue: false },
|
54
|
-
{ name: 'worker', type: Number, defaultValue: workerNum },
|
55
|
-
{ name: 'process-timeout', type: Number, defaultValue: 60 },
|
56
|
-
{ name: 'worker-timeout', type: Number, defaultValue: parseInt(process.env['WORKER_TIMEOUT_SECONDS'] || '60') },
|
57
|
-
{
|
58
|
-
name: 'enable-partition',
|
59
|
-
type: Boolean,
|
60
|
-
defaultValue: process.env['SENTIO_ENABLE_BINDING_DATA_PARTITION'] === 'true'
|
36
|
+
|
37
|
+
function myParseInt(value: string, dummyPrevious: unknown): number {
|
38
|
+
// parseInt takes a string and a radix
|
39
|
+
const parsedValue = parseInt(value, 10)
|
40
|
+
if (isNaN(parsedValue)) {
|
41
|
+
throw new InvalidArgumentError('Not a number.')
|
61
42
|
}
|
62
|
-
|
43
|
+
return parsedValue
|
44
|
+
}
|
63
45
|
|
64
|
-
|
46
|
+
// Create Commander.js program
|
47
|
+
const program = new Command()
|
65
48
|
|
66
|
-
|
49
|
+
program
|
50
|
+
.name('processor-runner')
|
51
|
+
.description('Sentio Processor Runtime')
|
52
|
+
.version('2.0.0-development')
|
53
|
+
.option('--target <path>', 'Path to the processor module to load')
|
54
|
+
.option('-p, --port <port>', 'Port to listen on', '4000')
|
55
|
+
.option('--concurrency <number>', 'Number of concurrent workers', myParseInt, 4)
|
56
|
+
.option('--batch-count <number>', 'Batch count for processing', myParseInt, 1)
|
57
|
+
.option('-c, --chains-config <path>', 'Path to chains configuration file', 'chains-config.json')
|
58
|
+
.option('--chainquery-server <url>', 'Chain query server URL', '')
|
59
|
+
.option('--pricefeed-server <url>', 'Price feed server URL', '')
|
60
|
+
.option('--log-format <format>', 'Log format (console|json)', 'console')
|
61
|
+
.option('--debug', 'Enable debug mode', false)
|
62
|
+
.option('--otlp-debug', 'Enable OTLP debug mode', false)
|
63
|
+
.option('--start-action-server', 'Start action server instead of processor server', false)
|
64
|
+
.option('--worker <number>', 'Number of worker threads', myParseInt, workerNum)
|
65
|
+
.option('--process-timeout <seconds>', 'Process timeout in seconds', myParseInt, 60)
|
66
|
+
.option(
|
67
|
+
'--worker-timeout <seconds>',
|
68
|
+
'Worker timeout in seconds',
|
69
|
+
myParseInt,
|
70
|
+
parseInt(process.env['WORKER_TIMEOUT_SECONDS'] || '60')
|
71
|
+
)
|
72
|
+
.option(
|
73
|
+
'--enable-partition',
|
74
|
+
'Enable binding data partition',
|
75
|
+
process.env['SENTIO_ENABLE_BINDING_DATA_PARTITION'] === 'true'
|
76
|
+
)
|
77
|
+
.action(async (options: any) => {
|
78
|
+
try {
|
79
|
+
await startServer(options)
|
80
|
+
} catch (error) {
|
81
|
+
console.error('Failed to start server:', error)
|
82
|
+
process.exit(1)
|
83
|
+
}
|
84
|
+
})
|
67
85
|
|
68
|
-
|
69
|
-
|
86
|
+
// Parse arguments
|
87
|
+
program.parse()
|
70
88
|
|
71
|
-
|
89
|
+
async function startServer(options: any): Promise<void> {
|
90
|
+
const logLevel = process.env['LOG_LEVEL']?.toLowerCase()
|
72
91
|
|
73
|
-
|
92
|
+
setupLogger(options['log-format'] === 'json', logLevel === 'debug' ? true : options.debug)
|
93
|
+
console.debug('Starting with', options.target)
|
74
94
|
|
75
|
-
|
95
|
+
await setupOTLP(options['otlp-debug'])
|
76
96
|
|
77
|
-
|
97
|
+
Error.stackTraceLimit = 20
|
78
98
|
|
79
|
-
|
80
|
-
let baseService: ProcessorServiceImpl | ServiceManager
|
81
|
-
const loader = async () => {
|
82
|
-
const m = await import(options.target)
|
83
|
-
console.debug('Module loaded', m)
|
84
|
-
return m
|
85
|
-
}
|
86
|
-
if (options['start-action-server']) {
|
87
|
-
server = new ActionServer(loader)
|
88
|
-
server.listen(options.port)
|
89
|
-
} else {
|
90
|
-
server = createServer({
|
91
|
-
'grpc.max_send_message_length': 768 * 1024 * 1024,
|
92
|
-
'grpc.max_receive_message_length': 768 * 1024 * 1024,
|
93
|
-
'grpc.default_compression_algorithm': compressionAlgorithms.gzip
|
94
|
-
})
|
95
|
-
// .use(prometheusServerMiddleware())
|
96
|
-
.use(openTelemetryServerMiddleware())
|
97
|
-
.use(errorDetailsServerMiddleware)
|
99
|
+
configureEndpoints(options)
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
console.debug('Starting Server', options)
|
102
|
+
|
103
|
+
let server: any
|
104
|
+
let baseService: ProcessorServiceImpl | ServiceManager
|
105
|
+
const loader = async () => {
|
106
|
+
const m = await import(options.target)
|
107
|
+
console.debug('Module loaded', m)
|
108
|
+
return m
|
103
109
|
}
|
110
|
+
if (options['start-action-server']) {
|
111
|
+
server = new ActionServer(loader)
|
112
|
+
server.listen(options.port)
|
113
|
+
} else {
|
114
|
+
server = createServer({
|
115
|
+
'grpc.max_send_message_length': 768 * 1024 * 1024,
|
116
|
+
'grpc.max_receive_message_length': 768 * 1024 * 1024,
|
117
|
+
'grpc.default_compression_algorithm': compressionAlgorithms.gzip
|
118
|
+
})
|
119
|
+
// .use(prometheusServerMiddleware())
|
120
|
+
.use(openTelemetryServerMiddleware())
|
121
|
+
.use(errorDetailsServerMiddleware)
|
104
122
|
|
105
|
-
|
123
|
+
if (options.worker > 1) {
|
124
|
+
baseService = new ServiceManager(loader, options, server.shutdown)
|
125
|
+
} else {
|
126
|
+
baseService = new ProcessorServiceImpl(loader, options, server.shutdown)
|
127
|
+
}
|
106
128
|
|
107
|
-
|
108
|
-
server.add(
|
109
|
-
ProcessorV3Definition,
|
110
|
-
new FullProcessorServiceV3Impl(new ProcessorServiceImplV3(loader, options, server.shutdown))
|
111
|
-
)
|
112
|
-
server.listen('0.0.0.0:' + options.port)
|
129
|
+
const service = new FullProcessorServiceImpl(baseService)
|
113
130
|
|
114
|
-
|
115
|
-
|
131
|
+
server.add(ProcessorDefinition, service)
|
132
|
+
server.add(
|
133
|
+
ProcessorV3Definition,
|
134
|
+
new FullProcessorServiceV3Impl(new ProcessorServiceImplV3(loader, options, server.shutdown))
|
135
|
+
)
|
116
136
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
server.listen('0.0.0.0:' + options.port)
|
138
|
+
console.log('Processor Server Started at:', options.port)
|
139
|
+
}
|
140
|
+
const metricsPort = 4040
|
141
|
+
|
142
|
+
const httpServer = http
|
143
|
+
.createServer(async function (req, res) {
|
144
|
+
if (req.url) {
|
145
|
+
const reqUrl = new URL(req.url, `http://${req.headers.host}`)
|
146
|
+
const queries = reqUrl.searchParams
|
147
|
+
switch (reqUrl.pathname) {
|
148
|
+
// case '/metrics':
|
149
|
+
// const metrics = await mergedRegistry.metrics()
|
150
|
+
// res.write(metrics)
|
151
|
+
// break
|
152
|
+
case '/heap': {
|
153
|
+
try {
|
154
|
+
const file = '/tmp/' + Date.now() + '.heapsnapshot'
|
155
|
+
await dumpHeap(file)
|
156
|
+
// send the file
|
157
|
+
const readStream = fs.createReadStream(file)
|
158
|
+
res.writeHead(200, { 'Content-Type': 'application/json' })
|
159
|
+
readStream.pipe(res)
|
160
|
+
res.end()
|
161
|
+
} catch {
|
162
|
+
res.writeHead(500)
|
163
|
+
res.end()
|
164
|
+
}
|
165
|
+
break
|
141
166
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
167
|
+
case '/profile': {
|
168
|
+
try {
|
169
|
+
const profileTime = parseInt(queries.get('t') || '1000', 10) || 1000
|
170
|
+
const session = new Session()
|
171
|
+
session.connect()
|
172
|
+
|
173
|
+
await session.post('Profiler.enable')
|
174
|
+
await session.post('Profiler.start')
|
175
|
+
|
176
|
+
await new Promise((resolve) => setTimeout(resolve, profileTime))
|
177
|
+
const { profile } = await session.post('Profiler.stop')
|
178
|
+
|
179
|
+
res.writeHead(200, { 'Content-Type': 'application/json' })
|
180
|
+
res.write(JSON.stringify(profile))
|
181
|
+
session.disconnect()
|
182
|
+
} catch {
|
183
|
+
res.writeHead(500)
|
184
|
+
}
|
185
|
+
break
|
161
186
|
}
|
162
|
-
|
187
|
+
default:
|
188
|
+
res.writeHead(404)
|
163
189
|
}
|
164
|
-
|
165
|
-
|
190
|
+
} else {
|
191
|
+
res.writeHead(404)
|
166
192
|
}
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
res.end()
|
171
|
-
})
|
172
|
-
.listen(metricsPort)
|
193
|
+
res.end()
|
194
|
+
})
|
195
|
+
.listen(metricsPort)
|
173
196
|
|
174
|
-
console.log('Metric Server Started at:', metricsPort)
|
197
|
+
console.log('Metric Server Started at:', metricsPort)
|
175
198
|
|
176
|
-
process
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
199
|
+
process
|
200
|
+
.on('SIGINT', function () {
|
201
|
+
shutdownServers(server, httpServer, 0)
|
202
|
+
})
|
203
|
+
.on('uncaughtException', (err) => {
|
204
|
+
console.error('Uncaught Exception, please checking if await is properly used', err)
|
205
|
+
if (baseService) {
|
206
|
+
baseService.unhandled = err
|
207
|
+
}
|
208
|
+
// shutdownServers(1)
|
209
|
+
})
|
210
|
+
.on('unhandledRejection', (reason, p) => {
|
211
|
+
// @ts-ignore ignore invalid ens error
|
212
|
+
if (reason?.message.startsWith('invalid ENS name (disallowed character: "*"')) {
|
213
|
+
return
|
214
|
+
}
|
215
|
+
console.error('Unhandled Rejection, please checking if await is properly', reason)
|
216
|
+
if (baseService) {
|
217
|
+
baseService.unhandled = reason as Error
|
218
|
+
}
|
219
|
+
// shutdownServers(1)
|
220
|
+
})
|
198
221
|
|
199
|
-
if (process.env['OOM_DUMP_MEMORY_SIZE_GB']) {
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
222
|
+
if (process.env['OOM_DUMP_MEMORY_SIZE_GB']) {
|
223
|
+
let dumping = false
|
224
|
+
const memorySize = parseFloat(process.env['OOM_DUMP_MEMORY_SIZE_GB']!)
|
225
|
+
console.log('heap dumping is enabled, limit set to ', memorySize, 'gb')
|
226
|
+
const dir = process.env['OOM_DUMP_DIR'] || '/tmp'
|
227
|
+
setInterval(async () => {
|
228
|
+
const mem = process.memoryUsage()
|
229
|
+
console.log('Current Memory Usage', mem)
|
230
|
+
// if memory usage is greater this size, dump heap and exit
|
231
|
+
if (mem.heapTotal > memorySize * 1024 * 1024 * 1024 && !dumping) {
|
232
|
+
const file = path.join(dir, `${Date.now()}.heapsnapshot`)
|
233
|
+
dumping = true
|
234
|
+
await dumpHeap(file)
|
235
|
+
// force exit and keep pod running
|
236
|
+
process.exit(11)
|
237
|
+
}
|
238
|
+
}, 1000 * 60)
|
239
|
+
}
|
216
240
|
}
|
217
241
|
|
218
|
-
async function dumpHeap(file: string) {
|
242
|
+
async function dumpHeap(file: string): Promise<void> {
|
219
243
|
console.log('Heap dumping to', file)
|
220
244
|
const session = new Session()
|
221
245
|
fs.mkdirSync(path.dirname(file), { recursive: true })
|
@@ -234,7 +258,7 @@ async function dumpHeap(file: string) {
|
|
234
258
|
}
|
235
259
|
}
|
236
260
|
|
237
|
-
function shutdownServers(exitCode: number) {
|
261
|
+
function shutdownServers(server: any, httpServer: any, exitCode: number): void {
|
238
262
|
server?.forceShutdown()
|
239
263
|
console.log('RPC server shut down')
|
240
264
|
|
package/src/service-manager.ts
CHANGED
@@ -139,7 +139,8 @@ export class ServiceManager extends ProcessorServiceImpl {
|
|
139
139
|
argv: process.argv,
|
140
140
|
workerData: this.workerData
|
141
141
|
})
|
142
|
-
|
142
|
+
// @ts-ignore - Piscina message handling for template instance sync
|
143
|
+
this.pool.on('message', (msg: any) => {
|
143
144
|
if (msg.event == 'add_template_instance') {
|
144
145
|
// sync the template state from worker to the main thread
|
145
146
|
TemplateInstanceState.INSTANCE.addValue(msg.value)
|