@outputai/core 0.6.0 → 0.6.1-next.34badf9.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.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/src/activity_integration/context.d.ts +5 -9
  3. package/src/activity_integration/context.js +5 -4
  4. package/src/activity_integration/context.spec.js +10 -15
  5. package/src/activity_integration/events.d.ts +2 -4
  6. package/src/activity_integration/events.js +8 -3
  7. package/src/activity_integration/events.spec.js +58 -29
  8. package/src/bus.js +18 -9
  9. package/src/bus.spec.js +30 -0
  10. package/src/hooks/index.d.ts +112 -58
  11. package/src/hooks/index.js +15 -12
  12. package/src/hooks/index.spec.js +60 -32
  13. package/src/interface/workflow.js +19 -35
  14. package/src/interface/workflow.spec.js +104 -15
  15. package/src/internal_activities/index.js +3 -3
  16. package/src/internal_activities/index.spec.js +31 -1
  17. package/src/internal_utils/temporal_context.js +12 -0
  18. package/src/internal_utils/temporal_context.spec.ts +83 -0
  19. package/src/internal_utils/trace_info.js +21 -0
  20. package/src/internal_utils/trace_info.spec.js +47 -0
  21. package/src/internal_utils/workflow_context.js +29 -0
  22. package/src/internal_utils/workflow_context.spec.js +46 -0
  23. package/src/tracing/internal_interface.js +4 -4
  24. package/src/tracing/processors/local/index.js +21 -26
  25. package/src/tracing/processors/local/index.spec.js +39 -45
  26. package/src/tracing/processors/s3/index.js +13 -23
  27. package/src/tracing/processors/s3/index.spec.js +33 -26
  28. package/src/tracing/trace_attribute.js +0 -1
  29. package/src/tracing/trace_engine.js +8 -12
  30. package/src/tracing/trace_engine.spec.js +31 -27
  31. package/src/worker/interceptors/activity.js +31 -29
  32. package/src/worker/interceptors/activity.spec.js +58 -26
  33. package/src/worker/interceptors/workflow.js +7 -2
  34. package/src/worker/interceptors/workflow.spec.js +42 -6
  35. package/src/worker/log_hooks.js +35 -46
  36. package/src/worker/log_hooks.spec.js +43 -46
  37. package/src/worker/sinks.js +24 -24
  38. package/src/interface/workflow_context.js +0 -33
@@ -1,6 +1,6 @@
1
1
  import { messageBus } from '#bus';
2
2
  import { createChildLogger } from '#logger';
3
- import { BusEventType, ComponentType, LifecycleEvent, WORKFLOW_CATALOG } from '#consts';
3
+ import { ACTIVITY_GET_TRACE_DESTINATIONS, BusEventType, LifecycleEvent, WORKFLOW_CATALOG } from '#consts';
4
4
 
5
5
  const activityLog = createChildLogger( 'Activity' );
6
6
  const workflowLog = createChildLogger( 'Workflow' );
@@ -15,43 +15,34 @@ const workflowLog = createChildLogger( 'Workflow' );
15
15
  ╚═════════════════╝
16
16
  */
17
17
 
18
- /**
19
- * Returns true if activity event should be logged
20
- */
21
- const shouldLogActivityEvent = ( { kind } ) => kind !== ComponentType.INTERNAL_STEP;
18
+ const serializedActivityFields = activityInfo => ( {
19
+ activityId: activityInfo.activityId,
20
+ activityType: activityInfo.activityType,
21
+ workflowId: activityInfo.workflowExecution.workflowId,
22
+ workflowType: activityInfo.workflowType,
23
+ runId: activityInfo.workflowExecution.runId
24
+ } );
25
+
26
+ const shouldLogActivity = activityInfo => activityInfo.activityType !== ACTIVITY_GET_TRACE_DESTINATIONS;
22
27
 
23
- messageBus.on( BusEventType.ACTIVITY_START, ( { id, name, kind, workflowId, workflowName } ) =>
24
- shouldLogActivityEvent( { kind } ) && activityLog.info( `Started ${name} ${kind}`, {
28
+ messageBus.on( BusEventType.ACTIVITY_START, ( { activityInfo, outputActivityKind } ) =>
29
+ shouldLogActivity( activityInfo ) && activityLog.info( `Started ${activityInfo.activityType} ${outputActivityKind}`, {
25
30
  event: LifecycleEvent.START,
26
- activityId: id,
27
- activityName: name,
28
- activityKind: kind,
29
- workflowId,
30
- workflowName
31
+ ...serializedActivityFields( activityInfo )
31
32
  } )
32
33
  );
33
34
 
34
- messageBus.on( BusEventType.ACTIVITY_END, ( { id, name, kind, workflowId, workflowName, duration } ) =>
35
- shouldLogActivityEvent( { kind } ) && activityLog.info( `Ended ${name} ${kind}`, {
35
+ messageBus.on( BusEventType.ACTIVITY_END, ( { activityInfo, outputActivityKind } ) =>
36
+ shouldLogActivity( activityInfo ) && activityLog.info( `Ended ${activityInfo.activityType} ${outputActivityKind}`, {
36
37
  event: LifecycleEvent.END,
37
- activityId: id,
38
- activityName: name,
39
- activityKind: kind,
40
- workflowId,
41
- workflowName,
42
- durationMs: duration
38
+ ...serializedActivityFields( activityInfo )
43
39
  } )
44
40
  );
45
41
 
46
- messageBus.on( BusEventType.ACTIVITY_ERROR, ( { id, name, kind, workflowId, workflowName, duration, error } ) =>
47
- shouldLogActivityEvent( { kind } ) && activityLog.error( `Error ${name} ${kind}: ${error.constructor.name}`, {
42
+ messageBus.on( BusEventType.ACTIVITY_ERROR, ( { activityInfo, outputActivityKind, error } ) =>
43
+ shouldLogActivity( activityInfo ) && activityLog.error( `Error ${activityInfo.activityType} ${outputActivityKind}: ${error.constructor.name}`, {
48
44
  event: LifecycleEvent.ERROR,
49
- activityId: id,
50
- activityName: name,
51
- activityKind: kind,
52
- workflowId,
53
- workflowName,
54
- durationMs: duration,
45
+ ...serializedActivityFields( activityInfo ),
55
46
  error: error.message
56
47
  } )
57
48
  );
@@ -62,34 +53,32 @@ messageBus.on( BusEventType.ACTIVITY_ERROR, ( { id, name, kind, workflowId, work
62
53
  ╚═════════════════╝
63
54
  */
64
55
 
65
- /**
66
- * Returns true if activity event should be logged
67
- */
68
- const shouldLogWorkflowEvent = ( { name } ) => name !== WORKFLOW_CATALOG;
56
+ const serializeWorkflowFields = workflowDetails => ( {
57
+ workflowId: workflowDetails.workflowId,
58
+ workflowType: workflowDetails.workflowType,
59
+ runId: workflowDetails.runId
60
+ } );
61
+
62
+ const shouldLogWorkflow = workflowDetails => workflowDetails.workflowType !== WORKFLOW_CATALOG;
69
63
 
70
- messageBus.on( BusEventType.WORKFLOW_START, ( { id, name } ) =>
71
- shouldLogWorkflowEvent( { name } ) && workflowLog.info( `Started ${name} workflow`, {
64
+ messageBus.on( BusEventType.WORKFLOW_START, ( { workflowDetails } ) =>
65
+ shouldLogWorkflow( workflowDetails ) && workflowLog.info( `Started ${workflowDetails.workflowType} workflow`, {
72
66
  event: LifecycleEvent.START,
73
- workflowId: id,
74
- workflowName: name
67
+ ...serializeWorkflowFields( workflowDetails )
75
68
  } )
76
69
  );
77
70
 
78
- messageBus.on( BusEventType.WORKFLOW_END, ( { id, name, duration } ) =>
79
- shouldLogWorkflowEvent( { name } ) && workflowLog.info( `Ended ${name} workflow`, {
71
+ messageBus.on( BusEventType.WORKFLOW_END, ( { workflowDetails } ) =>
72
+ shouldLogWorkflow( workflowDetails ) && workflowLog.info( `Ended ${workflowDetails.workflowType} workflow`, {
80
73
  event: LifecycleEvent.END,
81
- workflowId: id,
82
- workflowName: name,
83
- durationMs: duration
74
+ ...serializeWorkflowFields( workflowDetails )
84
75
  } )
85
76
  );
86
77
 
87
- messageBus.on( BusEventType.WORKFLOW_ERROR, ( { id, name, duration, error } ) =>
88
- shouldLogWorkflowEvent( { name } ) && workflowLog.error( `Error ${name} workflow: ${error.constructor.name}`, {
78
+ messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, error } ) =>
79
+ shouldLogWorkflow( workflowDetails ) && workflowLog.error( `Error ${workflowDetails.workflowType} workflow: ${error.constructor.name}`, {
89
80
  event: LifecycleEvent.ERROR,
90
- workflowId: id,
91
- workflowName: name,
92
- durationMs: duration,
81
+ ...serializeWorkflowFields( workflowDetails ),
93
82
  error: error.message
94
83
  } )
95
84
  );
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import {
3
+ ACTIVITY_GET_TRACE_DESTINATIONS,
3
4
  BusEventType,
4
- ComponentType,
5
5
  LifecycleEvent,
6
6
  WORKFLOW_CATALOG
7
7
  } from '#consts';
@@ -30,12 +30,15 @@ describe( 'log_hooks', () => {
30
30
  } );
31
31
 
32
32
  describe( 'activity events', () => {
33
+ const activityInfo = {
34
+ activityId: 'act-1',
35
+ activityType: 'myWorkflow#myStep',
36
+ workflowExecution: { workflowId: 'wf-1', runId: 'run-1' },
37
+ workflowType: 'myWorkflow'
38
+ };
33
39
  const basePayload = {
34
- id: 'act-1',
35
- name: 'myWorkflow#myStep',
36
- kind: 'step',
37
- workflowId: 'wf-1',
38
- workflowName: 'myWorkflow'
40
+ activityInfo,
41
+ outputActivityKind: 'step'
39
42
  };
40
43
 
41
44
  it( 'ACTIVITY_START logs full message and second arg', () => {
@@ -47,18 +50,18 @@ describe( 'log_hooks', () => {
47
50
  {
48
51
  event: LifecycleEvent.START,
49
52
  activityId: 'act-1',
50
- activityName: 'myWorkflow#myStep',
51
- activityKind: 'step',
53
+ activityType: 'myWorkflow#myStep',
52
54
  workflowId: 'wf-1',
53
- workflowName: 'myWorkflow'
55
+ workflowType: 'myWorkflow',
56
+ runId: 'run-1'
54
57
  }
55
58
  );
56
59
  } );
57
60
 
58
- it( 'ACTIVITY_START does not log when kind is INTERNAL_STEP', () => {
61
+ it( 'ACTIVITY_START does not log trace destination activity', () => {
59
62
  onHandlers[BusEventType.ACTIVITY_START]( {
60
63
  ...basePayload,
61
- kind: ComponentType.INTERNAL_STEP
64
+ activityInfo: { ...activityInfo, activityType: ACTIVITY_GET_TRACE_DESTINATIONS }
62
65
  } );
63
66
 
64
67
  expect( activityLogMock.info ).not.toHaveBeenCalled();
@@ -73,20 +76,18 @@ describe( 'log_hooks', () => {
73
76
  {
74
77
  event: LifecycleEvent.END,
75
78
  activityId: 'act-1',
76
- activityName: 'myWorkflow#myStep',
77
- activityKind: 'step',
79
+ activityType: 'myWorkflow#myStep',
78
80
  workflowId: 'wf-1',
79
- workflowName: 'myWorkflow',
80
- durationMs: 42
81
+ workflowType: 'myWorkflow',
82
+ runId: 'run-1'
81
83
  }
82
84
  );
83
85
  } );
84
86
 
85
- it( 'ACTIVITY_END does not log when kind is INTERNAL_STEP', () => {
87
+ it( 'ACTIVITY_END does not log trace destination activity', () => {
86
88
  onHandlers[BusEventType.ACTIVITY_END]( {
87
89
  ...basePayload,
88
- kind: ComponentType.INTERNAL_STEP,
89
- duration: 10
90
+ activityInfo: { ...activityInfo, activityType: ACTIVITY_GET_TRACE_DESTINATIONS }
90
91
  } );
91
92
 
92
93
  expect( activityLogMock.info ).not.toHaveBeenCalled();
@@ -106,21 +107,19 @@ describe( 'log_hooks', () => {
106
107
  {
107
108
  event: LifecycleEvent.ERROR,
108
109
  activityId: 'act-1',
109
- activityName: 'myWorkflow#myStep',
110
- activityKind: 'step',
110
+ activityType: 'myWorkflow#myStep',
111
111
  workflowId: 'wf-1',
112
- workflowName: 'myWorkflow',
113
- durationMs: 100,
112
+ workflowType: 'myWorkflow',
113
+ runId: 'run-1',
114
114
  error: 'step failed'
115
115
  }
116
116
  );
117
117
  } );
118
118
 
119
- it( 'ACTIVITY_ERROR does not log when kind is INTERNAL_STEP', () => {
119
+ it( 'ACTIVITY_ERROR does not log trace destination activity', () => {
120
120
  onHandlers[BusEventType.ACTIVITY_ERROR]( {
121
121
  ...basePayload,
122
- kind: ComponentType.INTERNAL_STEP,
123
- duration: 5,
122
+ activityInfo: { ...activityInfo, activityType: ACTIVITY_GET_TRACE_DESTINATIONS },
124
123
  error: new Error( 'x' )
125
124
  } );
126
125
 
@@ -129,7 +128,12 @@ describe( 'log_hooks', () => {
129
128
  } );
130
129
 
131
130
  describe( 'workflow events', () => {
132
- const basePayload = { id: 'wf-1', name: 'myWorkflow' };
131
+ const workflowDetails = {
132
+ workflowId: 'wf-1',
133
+ workflowType: 'myWorkflow',
134
+ runId: 'run-1'
135
+ };
136
+ const basePayload = { workflowDetails };
133
137
 
134
138
  it( 'WORKFLOW_START logs full message and second arg', () => {
135
139
  onHandlers[BusEventType.WORKFLOW_START]( basePayload );
@@ -140,25 +144,22 @@ describe( 'log_hooks', () => {
140
144
  {
141
145
  event: LifecycleEvent.START,
142
146
  workflowId: 'wf-1',
143
- workflowName: 'myWorkflow'
147
+ workflowType: 'myWorkflow',
148
+ runId: 'run-1'
144
149
  }
145
150
  );
146
151
  } );
147
152
 
148
- it( 'WORKFLOW_START does not log when name is WORKFLOW_CATALOG', () => {
153
+ it( 'WORKFLOW_START does not log when workflowType is WORKFLOW_CATALOG', () => {
149
154
  onHandlers[BusEventType.WORKFLOW_START]( {
150
- id: 'cat-1',
151
- name: WORKFLOW_CATALOG
155
+ workflowDetails: { ...workflowDetails, workflowType: WORKFLOW_CATALOG }
152
156
  } );
153
157
 
154
158
  expect( workflowLogMock.info ).not.toHaveBeenCalled();
155
159
  } );
156
160
 
157
161
  it( 'WORKFLOW_END logs full message and second arg', () => {
158
- onHandlers[BusEventType.WORKFLOW_END]( {
159
- ...basePayload,
160
- duration: 200
161
- } );
162
+ onHandlers[BusEventType.WORKFLOW_END]( basePayload );
162
163
 
163
164
  expect( workflowLogMock.info ).toHaveBeenCalledTimes( 1 );
164
165
  expect( workflowLogMock.info ).toHaveBeenCalledWith(
@@ -166,17 +167,15 @@ describe( 'log_hooks', () => {
166
167
  {
167
168
  event: LifecycleEvent.END,
168
169
  workflowId: 'wf-1',
169
- workflowName: 'myWorkflow',
170
- durationMs: 200
170
+ workflowType: 'myWorkflow',
171
+ runId: 'run-1'
171
172
  }
172
173
  );
173
174
  } );
174
175
 
175
- it( 'WORKFLOW_END does not log when name is WORKFLOW_CATALOG', () => {
176
+ it( 'WORKFLOW_END does not log when workflowType is WORKFLOW_CATALOG', () => {
176
177
  onHandlers[BusEventType.WORKFLOW_END]( {
177
- id: 'cat-1',
178
- name: WORKFLOW_CATALOG,
179
- duration: 50
178
+ workflowDetails: { ...workflowDetails, workflowType: WORKFLOW_CATALOG }
180
179
  } );
181
180
 
182
181
  expect( workflowLogMock.info ).not.toHaveBeenCalled();
@@ -196,18 +195,16 @@ describe( 'log_hooks', () => {
196
195
  {
197
196
  event: LifecycleEvent.ERROR,
198
197
  workflowId: 'wf-1',
199
- workflowName: 'myWorkflow',
200
- durationMs: 150,
198
+ workflowType: 'myWorkflow',
199
+ runId: 'run-1',
201
200
  error: 'workflow boom'
202
201
  }
203
202
  );
204
203
  } );
205
204
 
206
- it( 'WORKFLOW_ERROR does not log when name is WORKFLOW_CATALOG', () => {
205
+ it( 'WORKFLOW_ERROR does not log when workflowType is WORKFLOW_CATALOG', () => {
207
206
  onHandlers[BusEventType.WORKFLOW_ERROR]( {
208
- id: 'cat-1',
209
- name: WORKFLOW_CATALOG,
210
- duration: 1,
207
+ workflowDetails: { ...workflowDetails, workflowType: WORKFLOW_CATALOG },
211
208
  error: new Error( 'x' )
212
209
  } );
213
210
 
@@ -1,6 +1,7 @@
1
1
  import { BusEventType, ComponentType } from '#consts';
2
2
  import * as Tracing from '#tracing';
3
3
  import { messageBus } from '#bus';
4
+ import { createWorkflowDetails } from '#internal_utils/temporal_context';
4
5
 
5
6
  // This sink allow for sandbox Temporal environment to send trace logs back to the main thread.
6
7
  export const sinks = {
@@ -11,10 +12,17 @@ export const sinks = {
11
12
  workflow: {
12
13
  start: {
13
14
  fn: ( workflowInfo, input ) => {
14
- const { workflowId: id, runId, workflowType: name, memo: { parentId, executionContext } } = workflowInfo;
15
- messageBus.emit( BusEventType.WORKFLOW_START, { id, runId, name } );
16
- if ( executionContext ) { // filters out internal workflows
17
- Tracing.addEventStart( { id, kind: ComponentType.WORKFLOW, name, details: input, parentId, executionContext } );
15
+ const { runId, workflowType, memo: { traceInfo }, parent } = workflowInfo;
16
+ messageBus.emit( BusEventType.WORKFLOW_START, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
17
+ if ( traceInfo ) { // internal workflows (catalog) do not have this info
18
+ Tracing.addEventStart( {
19
+ id: runId,
20
+ kind: ComponentType.WORKFLOW,
21
+ name: workflowType,
22
+ details: input,
23
+ parentId: parent?.runId,
24
+ traceInfo
25
+ } );
18
26
  }
19
27
  },
20
28
  callDuringReplay: false
@@ -22,10 +30,10 @@ export const sinks = {
22
30
 
23
31
  end: {
24
32
  fn: ( workflowInfo, output ) => {
25
- const { workflowId: id, runId, workflowType: name, startTime, memo: { executionContext } } = workflowInfo;
26
- messageBus.emit( BusEventType.WORKFLOW_END, { id, runId, name, duration: Date.now() - startTime.getTime() } );
27
- if ( executionContext ) { // filters out internal workflows
28
- Tracing.addEventEnd( { id, details: output, executionContext } );
33
+ const { runId, memo: { traceInfo } } = workflowInfo;
34
+ messageBus.emit( BusEventType.WORKFLOW_END, { workflowDetails: createWorkflowDetails( workflowInfo ) } );
35
+ if ( traceInfo ) { // internal workflows (catalog) do not have this info
36
+ Tracing.addEventEnd( { id: runId, details: output, traceInfo } );
29
37
  }
30
38
  },
31
39
  callDuringReplay: false
@@ -33,10 +41,10 @@ export const sinks = {
33
41
 
34
42
  error: {
35
43
  fn: ( workflowInfo, error ) => {
36
- const { workflowId: id, runId, workflowType: name, startTime, memo: { executionContext } } = workflowInfo;
37
- messageBus.emit( BusEventType.WORKFLOW_ERROR, { id, runId, name, error, duration: Date.now() - startTime.getTime() } );
38
- if ( executionContext ) { // filters out internal workflows
39
- Tracing.addEventError( { id, details: error, executionContext } );
44
+ const { runId, memo: { traceInfo } } = workflowInfo;
45
+ messageBus.emit( BusEventType.WORKFLOW_ERROR, { workflowDetails: createWorkflowDetails( workflowInfo ), error } );
46
+ if ( traceInfo ) { // internal workflows (catalog) do not have this info
47
+ Tracing.addEventError( { id: runId, details: error, traceInfo } );
40
48
  }
41
49
  },
42
50
  callDuringReplay: false
@@ -48,26 +56,18 @@ export const sinks = {
48
56
  */
49
57
  trace: {
50
58
  start: {
51
- fn: ( workflowInfo, { id, name, kind, details } ) => {
52
- const { memo: { executionContext, parentId } } = workflowInfo;
53
- Tracing.addEventStart( { id, kind, name, details, parentId, executionContext } );
54
- },
59
+ fn: ( workflowInfo, { id, name, kind, details } ) =>
60
+ Tracing.addEventStart( { id, kind, name, details, parentId: workflowInfo.parent?.runId, traceInfo: workflowInfo.memo.traceInfo } ),
55
61
  callDuringReplay: false
56
62
  },
57
63
 
58
64
  end: {
59
- fn: ( workflowInfo, { id, details } ) => {
60
- const { memo: { executionContext } } = workflowInfo;
61
- Tracing.addEventEnd( { id, details, executionContext } );
62
- },
65
+ fn: ( workflowInfo, { id, details } ) => Tracing.addEventEnd( { id, details, traceInfo: workflowInfo.memo.traceInfo } ),
63
66
  callDuringReplay: false
64
67
  },
65
68
 
66
69
  error: {
67
- fn: ( workflowInfo, { id, details } ) => {
68
- const { memo: { executionContext } } = workflowInfo;
69
- Tracing.addEventError( { id, details, executionContext } );
70
- },
70
+ fn: ( workflowInfo, { id, details } ) => Tracing.addEventError( { id, details, traceInfo: workflowInfo.memo.traceInfo } ),
71
71
  callDuringReplay: false
72
72
  }
73
73
  }
@@ -1,33 +0,0 @@
1
- /**
2
- * Context instance builder
3
- */
4
- export class Context {
5
-
6
- /**
7
- * Builds a new context instance
8
- * @param {object} options - Arguments to build a new context instance
9
- * @param {string} workflowId
10
- * @param {string} runId
11
- * @param {function} continueAsNew
12
- * @param {function} isContinueAsNewSuggested
13
- * @returns {object} context
14
- */
15
- static build( { workflowId, runId, continueAsNew, isContinueAsNewSuggested } ) {
16
- return {
17
- /**
18
- * Control namespace: This object adds functions to interact with Temporal flow mechanisms
19
- */
20
- control: {
21
- continueAsNew,
22
- isContinueAsNewSuggested
23
- },
24
- /**
25
- * Info namespace: abstracts workflowInfo()
26
- */
27
- info: {
28
- workflowId,
29
- runId
30
- }
31
- };
32
- }
33
- };