@live-change/framework 0.9.171 → 0.9.174

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/App.js CHANGED
@@ -37,9 +37,12 @@ import Debug from 'debug'
37
37
 
38
38
  const debug = Debug('framework')
39
39
 
40
-
40
+ import { expandObjectAttributes } from './utils.js'
41
41
  import * as utils from './utils.js'
42
42
  import * as validation from './utils/validation.js'
43
+ import { trace, SpanKind, context, propagation } from '@opentelemetry/api'
44
+
45
+
43
46
 
44
47
  class App {
45
48
 
@@ -89,6 +92,8 @@ class App {
89
92
  this.triggerRoutes = {}
90
93
  this.globalViews = {}
91
94
 
95
+ this.loggingHelpers = utils.loggingHelpers('live-change/app', '')
96
+ this.tracer = trace.getTracer('live-change/app')
92
97
  }
93
98
 
94
99
  static app() {
@@ -252,205 +257,263 @@ class App {
252
257
  }
253
258
 
254
259
  async trigger(trigger, data) {
255
- if(!trigger) throw new Error("trigger must have type")
256
- if(typeof trigger !== 'object') throw new Error("trigger must be object")
257
- if(typeof trigger.type !== 'string') throw new Error("trigger type must be string")
258
- if(!data) throw new Error("trigger must have data")
259
- if(typeof data !== 'object') throw new Error("trigger must be object")
260
- if(trigger.service) return await this.triggerService(trigger, data, true)
261
- if(this.shortTriggers) {
262
- const triggers = this.triggerRoutes[trigger.type] /// TODO: check if it is right
263
- return await Promise.all(triggers.map(t => t.execute(data)))
264
- }
265
- const profileOp = await this.profileLog.begin({
266
- operation: "callTrigger", triggerType: trigger.type, id: data.id, by: data.by
260
+ return this.tracer.startActiveSpan('callTrigger:'+trigger.type, {
261
+ kind: SpanKind.INTERNAL,
262
+ attributes: {
263
+ ...expandObjectAttributes(trigger, 'trigger'),
264
+ ...expandObjectAttributes(data, 'data'),
265
+ }
266
+ }, async (triggerSpan) => {
267
+ try {
268
+ if(!trigger) throw new Error("trigger must have type")
269
+ if(typeof trigger !== 'object') throw new Error("trigger must be object")
270
+ if(typeof trigger.type !== 'string') throw new Error("trigger type must be string")
271
+ if(!data) throw new Error("trigger must have data")
272
+ if(typeof data !== 'object') throw new Error("trigger must be object")
273
+ if(trigger.service) return await this.triggerService(trigger, data, true)
274
+ if(this.shortTriggers) {
275
+ const triggers = this.triggerRoutes[trigger.type] /// TODO: check if it is right
276
+ return await Promise.all(triggers.map(t => t.execute(data)))
277
+ }
278
+ const profileOp = await this.profileLog.begin({
279
+ operation: "callTrigger", triggerType: trigger.type, id: data.id, by: data.by
280
+ })
281
+ const routes = await this.dao.get(['database', 'tableRange', this.databaseName, 'triggerRoutes',
282
+ { gte: trigger.type+'=', lte: trigger.type+'=\xFF\xFF\xFF\xFF' }])
283
+ this.loggingHelpers.log("TRIGGER ROUTES", trigger.type, '=>', routes.map(r => r.service).join(', '))
284
+ let promises = []
285
+ for(const route of routes) {
286
+ promises.push(this.triggerService({ ...trigger, service: route.service }, { ...data }, true))
287
+ }
288
+ const promise = Promise.all(promises)
289
+ await this.profileLog.endPromise(profileOp, promise)
290
+ const result = (await promise).flat()
291
+ this.loggingHelpers.log("TRIGGER FINISHED!", result)
292
+ return result
293
+ } finally {
294
+ triggerSpan.end()
295
+ }
267
296
  })
268
- const routes = await this.dao.get(['database', 'tableRange', this.databaseName, 'triggerRoutes',
269
- { gte: trigger.type+'=', lte: trigger.type+'=\xFF\xFF\xFF\xFF' }])
270
- console.log("TRIGGER ROUTES", trigger.type, '=>', routes.map(r => r.service).join(', '))
271
- let promises = []
272
- for(const route of routes) {
273
- promises.push(this.triggerService({ ...trigger, service: route.service }, { ...data }, true))
274
- }
275
- const promise = Promise.all(promises)
276
- await this.profileLog.endPromise(profileOp, promise)
277
- const result = (await promise).flat()
278
- console.log("TRIGGER FINISHED!", result)
279
- return result
280
297
  }
281
298
 
282
299
  async triggerService(trigger, data, returnArray = false) {
283
- if(!trigger.service) throw new Error("trigger must have service")
284
- if(typeof trigger !== 'object') throw new Error("trigger must be object")
285
- if(typeof trigger.service !== 'string') throw new Error("trigger service must be string")
286
- if(typeof trigger.type !== 'string') throw new Error("trigger type must be string")
287
- trigger.data = data
288
- if(!trigger.data) throw new Error("trigger must have data")
289
- if(typeof trigger.data !== 'object') throw new Error("trigger must be object")
290
- if(this.shortTriggers) {
291
- const service = this.startedServices[trigger.service]
292
- const triggers = service.triggers[trigger.type]
293
- if(!triggers) return []
294
- const result = await Promise.all(triggers.map(t => t.execute(data)))
295
- if(!returnArray && Array.isArray(result) && result.length === 1) return result[0]
296
- return result
297
- }
298
- if(!trigger.id) trigger.id = this.generateUid()
299
- trigger.state = 'new'
300
- if(!trigger.timestamp) trigger.timestamp = (new Date()).toISOString()
300
+ return this.tracer.startActiveSpan('callTriggerService:'+trigger.service+'.'+trigger.type, {
301
+ kind: SpanKind.INTERNAL,
302
+ attributes: {
303
+ ...expandObjectAttributes(trigger, 'trigger'),
304
+ ...expandObjectAttributes(data, 'data'),
305
+ service: trigger.service
306
+ }
307
+ }, async (triggerSpan) => {
308
+ try {
309
+ if(!trigger.service) throw new Error("trigger must have service")
310
+ if(typeof trigger !== 'object') throw new Error("trigger must be object")
311
+ if(typeof trigger.service !== 'string') throw new Error("trigger service must be string")
312
+ if(typeof trigger.type !== 'string') throw new Error("trigger type must be string")
313
+ trigger.data = data
314
+ if(!trigger.data) throw new Error("trigger must have data")
315
+ if(typeof trigger.data !== 'object') throw new Error("trigger must be object")
316
+ if(this.shortTriggers) {
317
+ const service = this.startedServices[trigger.service]
318
+ const triggers = service.triggers[trigger.type]
319
+ if(!triggers) return []
320
+ const result = await Promise.all(triggers.map(t => t.execute(data)))
321
+ if(!returnArray && Array.isArray(result) && result.length === 1) return result[0]
322
+ return result
323
+ }
324
+ if(!trigger.id) trigger.id = this.generateUid()
325
+ trigger.state = 'new'
326
+ if(!trigger.timestamp) trigger.timestamp = (new Date()).toISOString()
301
327
 
302
- const profileOp = await this.profileLog.begin({
303
- operation: "callTriggerService", triggerType: trigger.type, service: trigger.service, triggerId: trigger.id, by: data.by
304
- })
328
+ const profileOp = await this.profileLog.begin({
329
+ operation: "callTriggerService", triggerType: trigger.type, service: trigger.service, triggerId: trigger.id, by: data.by
330
+ })
305
331
 
306
- const triggersTable = this.splitCommands ? `${this.name}_triggers` : 'triggers'
307
- const objectObservable = this.dao.observable(
308
- ['database', 'tableObject', this.databaseName, triggersTable, trigger.id],
309
- ReactiveDao.ObservableValue
310
- )
311
- await this.dao.request(['database', 'update', this.databaseName, triggersTable, trigger.id, [{
312
- op: 'conditional',
313
- conditions: [{ test: 'notExist', property: 'type' }],
314
- operations: [{ op: 'reverseMerge', value: trigger }],
315
- }]])
316
- let observer
317
- const promise = new Promise((resolve, reject) => {
318
- observer = (signal, value) => {
319
- if(signal !== 'set') return reject('unknownSignal')
320
- if(!value) return
321
- if(value.state === 'done') return resolve(value.result)
322
- if(value.state === 'failed') return reject(value.error)
332
+ const triggersTable = this.splitCommands ? `${this.name}_triggers` : 'triggers'
333
+ const objectObservable = this.dao.observable(
334
+ ['database', 'tableObject', this.databaseName, triggersTable, trigger.id],
335
+ ReactiveDao.ObservableValue
336
+ )
337
+
338
+ propagation.inject(context.active(), trigger._trace)
339
+
340
+ await this.dao.request(['database', 'update', this.databaseName, triggersTable, trigger.id, [{
341
+ op: 'conditional',
342
+ conditions: [{ test: 'notExist', property: 'type' }],
343
+ operations: [{ op: 'reverseMerge', value: trigger }],
344
+ }]])
345
+ let observer
346
+ const promise = new Promise((resolve, reject) => {
347
+ observer = (signal, value) => {
348
+ if(signal !== 'set') return reject('unknownSignal')
349
+ if(!value) return
350
+ if(value.state === 'done') return resolve(value.result)
351
+ if(value.state === 'failed') return reject(value.error)
352
+ }
353
+ objectObservable.observe(observer)
354
+ }).finally(() => {
355
+ objectObservable.unobserve(observer)
356
+ })
357
+ await this.profileLog.endPromise(profileOp, promise)
358
+
359
+ const result = await promise
360
+ if(!returnArray && Array.isArray(result) && result.length === 1) return result[0]
361
+ return result
362
+ } finally {
363
+ triggerSpan.end()
323
364
  }
324
- objectObservable.observe(observer)
325
- }).finally(() => {
326
- objectObservable.unobserve(observer)
327
365
  })
328
- await this.profileLog.endPromise(profileOp, promise)
329
-
330
- const result = await promise
331
- if(!returnArray && Array.isArray(result) && result.length === 1) return result[0]
332
- return result
333
366
  }
334
-
335
367
  async command(data, requestTimeout) {
336
- if(!data.id) data.id = this.generateUid()
337
- if(!data.service) throw new Error("command must have service")
338
- if(!data.type) throw new Error("command must have type")
339
- if(!data.timestamp) data.timestamp = (new Date()).toISOString()
340
- data.state = 'new'
341
-
342
- if(this.shortCommands) {
343
- const command = data
344
- const service = this.startedServices[data.service]
345
- const action = service.actions[data.type]
346
- const reportFinished = action.definition.waitForEvents ? command.id : undefined
347
- const flags = {commandId: command.id, reportFinished}
348
- const emit = (!this.splitEvents || this.shortEvents)
349
- ? new SingleEmitQueue(service, flags)
350
- : new SplitEmitQueue(service, flags)
351
- const queuedBy = action.definition.queuedBy
352
- if(queuedBy) {
353
- const profileOp = await service.profileLog.begin({
354
- operation: 'queueCommand', commandType: actionName,
355
- commandId: command.id, client: command.client
356
- })
357
- const keyFunction = typeof queuedBy == 'function' ? queuedBy : (
358
- Array.isArray(queuedBy) ? (c) => JSON.stringify(queuedBy.map(k => c[k])) :
359
- (c) => JSON.stringify(c[queuedBy]))
360
-
361
- const routine = () => service.profileLog.profile({
362
- operation: 'runCommand', commandType: actionName,
363
- commandId: command.id, client: command.client
364
- }, async () => {
365
- const result = await service.app.assertTime('command ' + action.definition.name,
366
- action.definition.timeout || 10000,
367
- () => action.runCommand(command, (...args) => emit.emit(...args)), command)
368
- if(this.shortEvents) {
369
- const bucket = {}
370
- const eventsPromise = Promise.all(emit.emittedEvents.map(event => {
371
- const service = this.startedServices[event.service]
372
- const handler = service.events[event.type]
373
- service.exentQueue.queue(() => handler.execute(event, bucket))
374
- }))
375
- if (action.definition.waitForEvents) await eventsPromise
368
+ return this.tracer.startActiveSpan('callCommand:'+data.service+'.'+data.type, {
369
+ kind: SpanKind.INTERNAL,
370
+ attributes: {
371
+ requestTimeout: requestTimeout,
372
+ ...expandObjectAttributes(data, 'command'),
373
+ }
374
+ }, async (commandSpan) => {
375
+ const testTrace = {}
376
+ propagation.inject(context.active(), testTrace)
377
+ try {
378
+
379
+ if(!data.id) data.id = this.generateUid()
380
+ if(!data.service) throw new Error("command must have service")
381
+ if(!data.type) throw new Error("command must have type")
382
+ if(!data.timestamp) data.timestamp = (new Date()).toISOString()
383
+ data.state = 'new'
384
+
385
+ if(this.shortCommands) {
386
+ const command = data
387
+ const service = this.startedServices[data.service]
388
+ const action = service.actions[data.type]
389
+ const queuedBy = action.definition.queuedBy
390
+ if(queuedBy) {
391
+ const profileOp = await service.profileLog.begin({
392
+ operation: 'queueCommand', commandType: actionName,
393
+ commandId: command.id, client: command.client
394
+ })
395
+ const keyFunction = typeof queuedBy == 'function' ? queuedBy : (
396
+ Array.isArray(queuedBy) ? (c) => JSON.stringify(queuedBy.map(k => c[k])) :
397
+ (c) => JSON.stringify(c[queuedBy]))
398
+
399
+ const _trace = {}
400
+ propagation.inject(context.active(), _trace)
401
+
402
+ const routine = () => service.profileLog.profile({
403
+ operation: 'runCommand', commandType: actionName,
404
+ commandId: command.id, client: command.client
405
+ }, async () => {
406
+ propagation.extract(context.active(), _trace)
407
+ const reportFinished = action.definition.waitForEvents ? command.id : undefined
408
+ propagation.inject(context.active(), _trace)
409
+ const flags = {commandId: command.id, reportFinished, _trace}
410
+ const emit = (!this.splitEvents || this.shortEvents)
411
+ ? new SingleEmitQueue(service, flags)
412
+ : new SplitEmitQueue(service, flags)
413
+
414
+ const result = await service.app.assertTime('command ' + action.definition.name,
415
+ action.definition.timeout || 10000,
416
+ () => action.runCommand(command, (...args) => emit.emit(...args)), command)
417
+ if(this.shortEvents) {
418
+ const bucket = {}
419
+ const eventsPromise = Promise.all(emit.emittedEvents.map(event => {
420
+ const service = this.startedServices[event.service]
421
+ const handler = service.events[event.type]
422
+ service.exentQueue.queue(() => handler.execute(event, bucket))
423
+ }))
424
+ if (action.definition.waitForEvents) await eventsPromise
425
+ } else {
426
+ const events = await emit.commit()
427
+ if (action.definition.waitForEvents)
428
+ await service.app.waitForEvents(reportFinished, events, action.definition.waitForEvents)
429
+ }
430
+ return result
431
+ })
432
+ routine.key = keyFunction(command)
433
+ const promise = service.keyBasedExecutionQueues.queue(routine)
434
+ await service.profileLog.endPromise(profileOp, promise)
435
+ return promise
376
436
  } else {
377
- const events = await emit.commit()
378
- if (action.definition.waitForEvents)
379
- await service.app.waitForEvents(reportFinished, events, action.definition.waitForEvents)
437
+ const result = await service.app.assertTime('command ' + action.definition.name,
438
+ action.definition.timeout || 10000,
439
+ () => action.runCommand(command, (...args) => emit.emit(...args)), command)
440
+ if(this.shortEvents) {
441
+ const bucket = {}
442
+ console.log("emit", emit)
443
+ const eventsPromise = Promise.all(emit.emittedEvents.map(event => {
444
+ const service = this.startedServices[event.service]
445
+ const handler = service.events[event.type]
446
+ service.exentQueue.queue(() => handler.execute(event, bucket))
447
+ }))
448
+ if (action.definition.waitForEvents) await eventsPromise
449
+ } else {
450
+ const events = await emit.commit()
451
+ if (action.definition.waitForEvents)
452
+ await service.app.waitForEvents(reportFinished, events, action.definition.waitForEvents)
453
+ }
454
+ return result
380
455
  }
381
- return result
382
- })
383
- routine.key = keyFunction(command)
384
- const promise = service.keyBasedExecutionQueues.queue(routine)
385
- await service.profileLog.endPromise(profileOp, promise)
386
- return promise
387
- } else {
388
- const result = await service.app.assertTime('command ' + action.definition.name,
389
- action.definition.timeout || 10000,
390
- () => action.runCommand(command, (...args) => emit.emit(...args)), command)
391
- if(this.shortEvents) {
392
- const bucket = {}
393
- console.log("emit", emit)
394
- const eventsPromise = Promise.all(emit.emittedEvents.map(event => {
395
- const service = this.startedServices[event.service]
396
- const handler = service.events[event.type]
397
- service.exentQueue.queue(() => handler.execute(event, bucket))
398
- }))
399
- if (action.definition.waitForEvents) await eventsPromise
400
- } else {
401
- const events = await emit.commit()
402
- if (action.definition.waitForEvents)
403
- await service.app.waitForEvents(reportFinished, events, action.definition.waitForEvents)
404
- }
405
- return result
406
- }
407
- } else { // queue and observe command execution
408
- const profileOp = await this.profileLog.begin({
409
- operation: "callCommand", commandType: data.type, service: data.service,
410
- commandId: data.id, by: data.by, client: data.client
411
- })
456
+ } else { // queue and observe command execution
457
+ const profileOp = await this.profileLog.begin({
458
+ operation: "callCommand", commandType: data.type, service: data.service,
459
+ commandId: data.id, by: data.by, client: data.client
460
+ })
461
+
462
+ const commandsTable = this.splitCommands ? `${data.service}_commands` : 'commands'
463
+ const objectObservable = this.dao.observable(
464
+ ['database', 'tableObject', this.databaseName, commandsTable, data.id],
465
+ ReactiveDao.ObservableValue
466
+ )
467
+
468
+ const _trace = {}
469
+ propagation.inject(context.active(), _trace)
470
+ data._trace = _trace
471
+ console.log("CALL COMMAND TRACE - SAVING TRACE", _trace)
472
+
473
+ await this.dao.request(['database', 'update', this.databaseName, commandsTable, data.id, [{
474
+ op: 'conditional',
475
+ conditions: [{ test: 'notExist', property: 'type' }],
476
+ operations: [{ op: 'reverseMerge', value: data }],
477
+ }]])
478
+ let observer
479
+ const promise = new Promise((resolve, reject) => {
480
+ observer = (signal, value) => {
481
+ if (signal !== 'set') return reject('unknownSignal')
482
+ if (!value) return
483
+ if (value.state === 'done') return resolve(value.result)
484
+ if (value.state === 'failed') return reject(value.error)
485
+ }
486
+ objectObservable.observe(observer)
487
+ if (!requestTimeout) {
488
+ requestTimeout = this.requestTimeout
489
+ }
490
+ if (requestTimeout) {
491
+ const timeout = setTimeout(() => {
492
+ this.activeTimeouts.delete(timeout)
493
+ reject('timeout')
494
+ }, requestTimeout)
495
+ this.activeTimeouts.add(timeout)
496
+ }
497
+ }).finally(() => {
498
+ objectObservable.unobserve(observer)
499
+ })
412
500
 
413
- const commandsTable = this.splitCommands ? `${data.service}_commands` : 'commands'
414
- const objectObservable = this.dao.observable(
415
- ['database', 'tableObject', this.databaseName, commandsTable, data.id],
416
- ReactiveDao.ObservableValue
417
- )
418
- await this.dao.request(['database', 'update', this.databaseName, commandsTable, data.id, [{
419
- op: 'conditional',
420
- conditions: [{ test: 'notExist', property: 'type' }],
421
- operations: [{ op: 'reverseMerge', value: data }],
422
- }]])
423
- let observer
424
- const promise = new Promise((resolve, reject) => {
425
- observer = (signal, value) => {
426
- if (signal !== 'set') return reject('unknownSignal')
427
- if (!value) return
428
- if (value.state === 'done') return resolve(value.result)
429
- if (value.state === 'failed') return reject(value.error)
430
- }
431
- objectObservable.observe(observer)
432
- if (!requestTimeout) {
433
- requestTimeout = this.requestTimeout
501
+ await this.profileLog.endPromise(profileOp, promise)
502
+ return promise
434
503
  }
435
- if (requestTimeout) {
436
- const timeout = setTimeout(() => {
437
- this.activeTimeouts.delete(timeout)
438
- reject('timeout')
439
- }, requestTimeout)
440
- this.activeTimeouts.add(timeout)
441
- }
442
- }).finally(() => {
443
- objectObservable.unobserve(observer)
444
- })
445
-
446
- await this.profileLog.endPromise(profileOp, promise)
447
- return promise
448
- }
504
+ } finally {
505
+ commandSpan.end()
506
+ }
507
+ })
449
508
  }
450
509
 
451
510
  async emitEvents(service, events, flags = {}) {
452
511
  for(let event of events) {
453
512
  if(!event.service) event.service = service
513
+ if(!event._trace) {
514
+ event._trace = {}
515
+ propagation.inject(context.active(), event._trace)
516
+ }
454
517
  }
455
518
  if(this.splitEvents) {
456
519
  let promises = []
@@ -476,73 +539,97 @@ class App {
476
539
 
477
540
  async waitForEvents(reportId, events, timeout) {
478
541
  if(events.length === 0) {
479
- console.log("no events, no need to wait", reportId)
542
+ this.loggingHelpers.log("no events, no need to wait", reportId)
480
543
  return
481
544
  }
482
545
  const [action, id] = reportId.split('_')
483
546
  const commandId = id
484
- const profileOp = await this.profileLog.begin({
485
- operation: "waitForEvents", action: action, commandId, reportId, events, timeout
486
- })
487
- const promise = new Promise((resolve, reject) => {
488
- let done = false
489
- let finishedEvents = []
490
- const handleError = (message) => {
491
- console.error(`waitForEvents error: `, message)
492
- const eventsNotDone = events.filter(event => finished.find(e => e.id === event.id))
493
- if(eventsNotDone.length > 0) {
494
- console.error(" pending events:")
495
- for(const event of eventsNotDone) {
496
- console.error(` ${event.id} - type: ${event.type}`)
497
- }
498
- }
499
- reject(message)
500
- done = true
547
+
548
+ return this.tracer.startActiveSpan('waitForEvents', {
549
+ kind: SpanKind.INTERNAL,
550
+ attributes: {
551
+ reportId: reportId,
552
+ eventTypes: events.map(e => e.type),
553
+ eventIds: events.map(e => e.id),
554
+ timeout: timeout
501
555
  }
502
- const observable = this.dao.observable(
503
- ['database', 'tableObject', this.databaseName, 'eventReports', reportId]
504
- )
505
- const reportsObserver = (signal, data) => {
506
- if(signal !== 'set') {
507
- handleError(`unknown signal ${signal} with data: ${data}`)
556
+ }, async (waitForEventsSpan) => {
557
+ const profileOp = await this.profileLog.begin({
558
+ operation: "waitForEvents", action: action, commandId, reportId, events, timeout
559
+ })
560
+ const _trace = {}
561
+ propagation.inject(context.active(), _trace)
562
+ const promise = new Promise((resolve, reject) => {
563
+ propagation.extract(context.active(), _trace)
564
+ let done = false
565
+ let finishedEvents = []
566
+ const handleError = (message) => {
567
+ let errorMessage = `waitForEvents error: ${message}`
568
+ const eventsNotDone = events.filter(event => finishedEvents.find(e => e.id === event.id))
569
+ if(eventsNotDone.length > 0) {
570
+ errorMessage += "\n pending events:"
571
+ for(const event of eventsNotDone) {
572
+ errorMessage += `\n ${event.id} - type: ${event.type}`
573
+ }
574
+ }
575
+ this.loggingHelpers.error(errorMessage)
576
+ reject(message)
577
+ done = true
508
578
  }
509
- if(data == null) return /// wait for real data
510
- if(data.finished) {
511
- finishedEvents = data.finished
512
- if(finishedEvents.length >= events.length) {
513
- const eventsNotDone = events.filter(event => data.finished.find(e => e.id === event.id))
514
- if(eventsNotDone.length !== 0) {
515
- const eventsDone = events.filter(event => !data.finished.find(e => e.id === event.id))
516
- console.error("waitForEvents - finished events does not match!")
517
- console.error(" finished events:")
518
- for(const event of eventsDone) {
519
- console.error(` ${event.id} - type: ${event.type}`)
520
- }
521
- console.error(" pending events:")
522
- for(const event of eventsNotDone) {
523
- console.error(` ${event.id} - type: ${event.type}`)
579
+ const observable = this.dao.observable(
580
+ ['database', 'tableObject', this.databaseName, 'eventReports', reportId]
581
+ )
582
+ const reportsObserver = (signal, data) => {
583
+ if(signal !== 'set') {
584
+ handleError(`unknown signal ${signal} with data: ${data}`)
585
+ }
586
+ if(data == null) return /// wait for real data
587
+ if(data.finished) {
588
+ finishedEvents = data.finished
589
+ if(finishedEvents.length >= events.length) {
590
+ const eventsNotDone = events.filter(event => data.finished.find(e => e.id === event.id))
591
+ if(eventsNotDone.length !== 0) {
592
+ const eventsDone = events.filter(event => !data.finished.find(e => e.id === event.id))
593
+ let errorMessage = "waitForEvents - finished events does not match!"
594
+ errorMessage += "\n finished events:"
595
+ for(const event of eventsDone) {
596
+ errorMessage += `\n ${event.id} - type: ${event.type}`
597
+ }
598
+ errorMessage += "\n pending events:"
599
+ for(const event of eventsNotDone) {
600
+ errorMessage += `\n ${event.id} - type: ${event.type}`
601
+ }
602
+ this.loggingHelpers.error(errorMessage)
603
+ } else {
604
+ this.loggingHelpers.log("waiting for events finished", reportId)
605
+ resolve('finished')
606
+ observable.unobserve(reportsObserver)
524
607
  }
525
- } else {
526
- console.log("waiting for events finished", reportId)
527
- resolve('finished')
528
- observable.unobserve(reportsObserver)
529
608
  }
530
609
  }
531
610
  }
532
- }
533
- console.log("waiting for events", reportId)
534
- observable.observe(reportsObserver)
535
- if(Number.isFinite(timeout)) {
536
- setTimeout(() => {
537
- if(done) return
538
- observable.unobserve(reportsObserver)
539
- console.error("events timeout", reportId)
540
- handleError('timeout')
541
- }, timeout)
542
- }
543
- })
544
- await this.profileLog.endPromise(profileOp, promise)
545
- return promise
611
+ this.loggingHelpers.log("waiting for events", reportId)
612
+ observable.observe(reportsObserver)
613
+ if(Number.isFinite(timeout)) {
614
+ setTimeout(() => {
615
+ if(done) return
616
+ observable.unobserve(reportsObserver)
617
+ this.loggingHelpers.error("events timeout", reportId)
618
+ handleError('timeout')
619
+ }, timeout)
620
+ }
621
+ })
622
+ await this.profileLog.endPromise(profileOp, promise)
623
+ promise.then(() => {
624
+ waitForEventsSpan.end()
625
+ })
626
+ promise.catch((error) => {
627
+ this.loggingHelpers.error("waitForEvents error", error)
628
+ waitForEventsSpan.end()
629
+ throw error
630
+ })
631
+ return promise
632
+ })
546
633
  }
547
634
 
548
635
  async emitEventsAndWait(service, events, flags = {}) {
@@ -554,7 +641,8 @@ class App {
554
641
  async assertTime(taskName, duration, task, ...data) {
555
642
  const profileOp = await this.profileLog.begin({ operation: 'assertTime', taskName })
556
643
  const taskTimeout = setTimeout(() => {
557
- console.log(`TASK ${taskName} TIMEOUT`, ...data)
644
+ this.loggingHelpers.error(`TASK ${taskName} TIMEOUT`, ...data)
645
+ //console.log(`TASK ${taskName} TIMEOUT`, ...data)
558
646
  this.profileLog.end({ ...profileOp, result: "timeout" })
559
647
  }, duration)
560
648
  try {