@things-factory/integration-base 7.0.0-alpha.4 → 7.0.0-alpha.7

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/dist-server/controllers/index.js +5 -0
  2. package/dist-server/controllers/index.js.map +1 -0
  3. package/dist-server/controllers/scenario-controller.js +87 -0
  4. package/dist-server/controllers/scenario-controller.js.map +1 -0
  5. package/dist-server/engine/connector/oracle-connector.js +113 -17
  6. package/dist-server/engine/connector/oracle-connector.js.map +1 -1
  7. package/dist-server/engine/task/oracle-procedure.js +1 -15
  8. package/dist-server/engine/task/oracle-procedure.js.map +1 -1
  9. package/dist-server/index.js +1 -0
  10. package/dist-server/index.js.map +1 -1
  11. package/dist-server/restful/unstable/run-scenario.js.map +1 -1
  12. package/dist-server/restful/unstable/start-scenario.js +1 -1
  13. package/dist-server/restful/unstable/start-scenario.js.map +1 -1
  14. package/dist-server/restful/unstable/stop-scenario.js +1 -1
  15. package/dist-server/restful/unstable/stop-scenario.js.map +1 -1
  16. package/dist-server/service/scenario-instance/scenario-instance-mutation.js +4 -71
  17. package/dist-server/service/scenario-instance/scenario-instance-mutation.js.map +1 -1
  18. package/dist-server/service/scenario-instance/scenario-instance-type.js +6 -1
  19. package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
  20. package/dist-server/tsconfig.tsbuildinfo +1 -1
  21. package/helps/integration/connector/oracle-connector.ja.md +90 -0
  22. package/helps/integration/connector/oracle-connector.ko.md +87 -0
  23. package/helps/integration/connector/oracle-connector.md +46 -25
  24. package/helps/integration/connector/oracle-connector.ms.md +87 -0
  25. package/helps/integration/connector/oracle-connector.zh.md +87 -0
  26. package/openapi/unstable/scenario.yaml +100 -100
  27. package/openapi/unstable.yaml +11 -11
  28. package/package.json +7 -7
  29. package/server/controllers/index.ts +1 -0
  30. package/server/controllers/scenario-controller.ts +116 -0
  31. package/server/engine/connector/oracle-connector.ts +132 -22
  32. package/server/engine/task/oracle-procedure.ts +1 -16
  33. package/server/index.ts +1 -0
  34. package/server/restful/unstable/run-scenario.ts +0 -1
  35. package/server/restful/unstable/start-scenario.ts +1 -1
  36. package/server/restful/unstable/stop-scenario.ts +1 -1
  37. package/server/service/scenario-instance/scenario-instance-mutation.ts +10 -121
  38. package/server/service/scenario-instance/scenario-instance-type.ts +11 -8
@@ -4,9 +4,8 @@ import { ConnectionManager } from '../connection-manager'
4
4
  import { Connector } from '../types'
5
5
  import { InputConnection } from '../../service/connection/connection-type'
6
6
 
7
-
8
7
  try {
9
- var Client = require('oracledb')
8
+ var oracledb = require('oracledb')
10
9
  } catch (err) {
11
10
  logger.error('oracledb module loading failed')
12
11
  }
@@ -18,42 +17,132 @@ export class OracleConnector implements Connector {
18
17
  ConnectionManager.logger.info('oracle-connector connections are ready')
19
18
  }
20
19
 
21
- async connect(connection: InputConnection) {
20
+ async recreatePool(connection: InputConnection) {
22
21
  const {
22
+ name,
23
23
  endpoint,
24
- params: { user, password, database }
24
+ params: { user, password, database, poolMin, poolMax, poolIncrement },
25
+ domain
25
26
  } = connection
26
27
 
27
- if (!Client) {
28
+ if (!oracledb) {
28
29
  throw new Error('oracledb module loading failed')
29
30
  }
30
31
 
31
- //when oracle not using default port must add connection string with port like localhsot:port
32
- const client = await Client.getConnection({
32
+ const poolAlias = `${domain.name}-${name}`
33
+ await oracledb.getPool(poolAlias).close(10)
34
+ await oracledb.createPool({
33
35
  user,
34
36
  password,
35
- connectString: `${endpoint.trim()}/${database}`
37
+ // when oracle not using default port must add connection string with port like localhost:port
38
+ connectString: `${endpoint.trim()}/${database}`,
39
+ poolMin,
40
+ poolMax,
41
+ poolIncrement,
42
+ poolAlias
36
43
  })
37
44
 
45
+ ConnectionManager.logger.info(`Oracle Database(${connection.name}:${database}) at ${endpoint} recreated.`)
46
+ }
47
+
48
+ async connect(connection: InputConnection) {
49
+ const {
50
+ name,
51
+ endpoint,
52
+ params: { user, password, database, poolMin, poolMax, poolIncrement },
53
+ domain
54
+ } = connection
55
+
56
+ if (!oracledb) {
57
+ throw new Error('oracledb module loading failed')
58
+ }
59
+
60
+ const poolAlias = `${domain.name}-${name}`
61
+
62
+ var enableStatistics = true
63
+ const pool = await oracledb.createPool({
64
+ user,
65
+ password,
66
+ // when oracle not using default port must add connection string with port like localhost:port
67
+ connectString: `${endpoint.trim()}/${database}`,
68
+ poolMin,
69
+ poolMax,
70
+ poolIncrement,
71
+ poolAlias,
72
+ enableStatistics
73
+ })
74
+
38
75
  ConnectionManager.addConnectionInstance(connection, {
39
76
  query: async (query, params) => {
40
- return (
41
- await client.execute(query, params, {
42
- outFormat: Client.OBJECT
43
- })
44
- ).rows
77
+ let dbConnection: any = {}
78
+ let taskResult: any = {}
79
+ try {
80
+ dbConnection = await oracledb.getConnection(poolAlias)
81
+
82
+ taskResult = (
83
+ await dbConnection.execute(query, params, {
84
+ outFormat: oracledb.OBJECT
85
+ })
86
+ ).rows
87
+ } catch (e) {
88
+ if (e.name === 'Error' && e.message.includes('NJS-040')) {
89
+ await this.recreatePool(connection)
90
+ }
91
+ throw e
92
+ }
93
+ finally {
94
+ await dbConnection.close()
95
+ }
96
+ return taskResult
97
+
45
98
  },
46
99
  execute: async (procedure, params) => {
47
- // TODO: need to check if this is available when procedure string is a common query.
48
- procedure = `BEGIN
49
- ${procedure}
50
- END;`
51
-
52
- return await client.execute(procedure, params, {
53
- outFormat: Client.OBJECT
54
- })
100
+ let dbConnection: any = {}
101
+ let taskResult: any = {}
102
+ try {
103
+ // TODO: need to check if this is available when procedure string is a common query.
104
+ procedure = `BEGIN
105
+ ${procedure}
106
+ END;`
107
+ dbConnection = await oracledb.getConnection(poolAlias)
108
+
109
+ // console.log('\n************* stat after get ****************')
110
+ // await oracledb.getPool(poolAlias).logStatistics()
111
+
112
+ const result = await dbConnection.execute(procedure, params, {
113
+ outFormat: oracledb.OBJECT
114
+ })
115
+
116
+ let paramKeys = Object.keys(params)
117
+
118
+ for (const paramKey of paramKeys) {
119
+ if (params[paramKey].dir === oracledb?.BIND_OUT) {
120
+ if (params[paramKey].type === oracledb?.CURSOR) {
121
+ const resultSetTemp = result.outBinds[paramKey]
122
+ taskResult[paramKey] = await resultSetTemp.getRows()
123
+ await resultSetTemp.close()
124
+ } else {
125
+ taskResult[paramKey] = result.outBinds[paramKey]
126
+ }
127
+ }
128
+ }
129
+ } catch (e) {
130
+ if (e.name === 'Error' && e.message.includes('NJS-040')) {
131
+ await this.recreatePool(connection)
132
+ }
133
+ throw e
134
+ }
135
+ finally {
136
+ await dbConnection.close()
137
+
138
+ // console.log('\n************* stat after close ****************')
139
+ // await oracledb.getPool(poolAlias).logStatistics()
140
+ }
141
+ return taskResult
55
142
  },
56
- close: client.close.bind(client)
143
+ close: async () => {
144
+ await oracledb.getPool(poolAlias).close(10)
145
+ }
57
146
  })
58
147
 
59
148
  ConnectionManager.logger.info(`Oracle Database(${connection.name}:${database}) at ${endpoint} connected.`)
@@ -89,6 +178,27 @@ export class OracleConnector implements Connector {
89
178
  name: 'database',
90
179
  placeholder: 'SID',
91
180
  label: 'database'
181
+ },
182
+ {
183
+ type: 'number',
184
+ name: 'poolMin',
185
+ placeholder: 'minimum connection-pool size',
186
+ label: 'pool-min',
187
+ value: 0
188
+ },
189
+ {
190
+ type: 'number',
191
+ name: 'poolMax',
192
+ placeholder: 'maximum connection-pool size',
193
+ label: 'pool-max',
194
+ value: 4
195
+ },
196
+ {
197
+ type: 'number',
198
+ name: 'poolIncrement',
199
+ placeholder: 'connection incremental size',
200
+ label: 'pool-increment',
201
+ value: 1
92
202
  }
93
203
  ]
94
204
  }
@@ -97,23 +97,8 @@ async function OracleProcedure(step: InputStep, context: Context) {
97
97
 
98
98
  const result = await dbconnection.execute(code, procedureParameters)
99
99
 
100
- var taskResult = {}
101
- let paramKeys = Object.keys(procedureParameters)
102
-
103
- for (const paramKey of paramKeys) {
104
- if (procedureParameters[paramKey].dir === oracledb?.BIND_OUT) {
105
- if (procedureParameters[paramKey].type === oracledb?.CURSOR) {
106
- const resultSetTemp = result.outBinds[paramKey]
107
- taskResult[paramKey] = await resultSetTemp.getRows()
108
- await resultSetTemp.close()
109
- } else {
110
- taskResult[paramKey] = result.outBinds[paramKey]
111
- }
112
- }
113
- }
114
-
115
100
  return {
116
- data: taskResult
101
+ data: result
117
102
  }
118
103
  }
119
104
 
package/server/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './migrations'
2
2
  export * from './engine'
3
+ export * from './controllers'
3
4
  export * from './service'
4
5
 
5
6
  import './routes'
@@ -1,7 +1,6 @@
1
1
  import gql from 'graphql-tag'
2
2
 
3
3
  import { restfulApiRouter as router } from '@things-factory/api'
4
- import { ScenarioInstanceStatus } from '../../service/scenario-instance/scenario-instance-type'
5
4
 
6
5
  const debug = require('debug')('things-factory:integration-base:restful:unstable:run-scenario')
7
6
 
@@ -12,7 +12,7 @@ router.post('/unstable/start-scenario/:scenarioName', async (context, next) => {
12
12
 
13
13
  context.body = await client.mutate({
14
14
  mutation: gql`
15
- mutation($instanceName: String, $scenarioName: String!, $variables: Object) {
15
+ mutation ($instanceName: String, $scenarioName: String!, $variables: Object) {
16
16
  startScenario(instanceName: $instanceName, scenarioName: $scenarioName, variables: $variables) {
17
17
  instanceName
18
18
  scenarioName
@@ -11,7 +11,7 @@ router.post('/unstable/stop-scenario/:instanceName', async (context, next) => {
11
11
 
12
12
  context.body = await client.mutate({
13
13
  mutation: gql`
14
- mutation($instanceName: String!) {
14
+ mutation ($instanceName: String!) {
15
15
  stopScenario(instanceName: $instanceName) {
16
16
  instanceName
17
17
  scenarioName
@@ -1,35 +1,14 @@
1
1
  import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
2
2
 
3
- import { getRepository, Domain, GraphqlLocalClient, ScalarObject } from '@things-factory/shell'
3
+ import { ScalarObject } from '@things-factory/shell'
4
4
 
5
- import { ScenarioEngine } from '../../engine'
6
- import { Scenario } from '../scenario/scenario'
7
5
  import { ScenarioInstance } from './scenario-instance-type'
8
- import { PrivilegeObject, User, checkPermission } from '@things-factory/auth-base'
9
- import { Step } from '../step/step-type'
10
6
 
11
- const debug = require('debug')('things-factory:integration-base:scenario-instance-mutation')
12
-
13
- async function findScenario(
14
- scenarioName: string,
15
- domain: Domain
16
- ): Promise<{ name: string; steps: Step[]; domain: Domain; privilege?: PrivilegeObject }> {
17
- var repository = getRepository(Scenario)
18
-
19
- var scenario = await repository.findOne({
20
- where: { domain: { id: domain.id }, name: scenarioName },
21
- relations: ['domain', 'steps', 'creator', 'updater']
22
- })
23
-
24
- if (!scenario && domain.parentId) {
25
- scenario = await repository.findOne({
26
- where: { domain: { id: domain.parentId }, name: scenarioName },
27
- relations: ['domain', 'steps', 'creator', 'updater']
28
- })
29
- }
30
-
31
- return scenario as any
32
- }
7
+ import {
8
+ runScenario as controllerRunScenario,
9
+ startScenario as controllerStartScenario,
10
+ stopScenario as controllerStopScenario
11
+ } from '../../controllers/scenario-controller'
33
12
 
34
13
  @Resolver(ScenarioInstance)
35
14
  export class ScenarioInstanceMutation {
@@ -42,42 +21,7 @@ export class ScenarioInstanceMutation {
42
21
  @Arg('variables', type => ScalarObject, { nullable: true }) variables: any,
43
22
  @Ctx() context: ResolverContext
44
23
  ): Promise<ScenarioInstance> {
45
- const { domain, user, lng, unsafeIP, prohibitedPrivileges } = context.state
46
-
47
- debug('runScenario', scenarioName, instanceName, variables)
48
-
49
- var scenario = await findScenario(scenarioName, domain)
50
-
51
- if (!scenario) {
52
- throw new Error(
53
- context.t('error.scenario not found', {
54
- scenario: scenarioName
55
- })
56
- )
57
- }
58
-
59
- if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
60
- const { category, privilege } = scenario.privilege || {}
61
- throw new Error(
62
- `Unauthorized! ${
63
- category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'
64
- } required`
65
- )
66
- }
67
-
68
- /* 시나리오 인스턴스를 생성한다. */
69
- instanceName = instanceName || scenarioName + '-' + String(Date.now())
70
- var instance = new ScenarioInstance(instanceName, scenario, {
71
- domain,
72
- user,
73
- lng,
74
- variables,
75
- client: GraphqlLocalClient.client
76
- })
77
-
78
- await instance.run()
79
-
80
- return instance
24
+ return await controllerRunScenario(instanceName, scenarioName, variables, context)
81
25
  }
82
26
 
83
27
  @Mutation(returns => ScenarioInstance, { description: 'To start new scenario instance' })
@@ -87,66 +31,11 @@ export class ScenarioInstanceMutation {
87
31
  @Arg('variables', type => ScalarObject, { nullable: true }) variables: any,
88
32
  @Ctx() context: ResolverContext
89
33
  ): Promise<ScenarioInstance> {
90
- const { domain, user, lng, unsafeIP, prohibitedPrivileges } = context.state
91
-
92
- debug('startScenario', instanceName, scenarioName, variables)
93
-
94
- var scenario = await findScenario(scenarioName, domain)
95
-
96
- if (!scenario) {
97
- throw new Error(
98
- context.t('error.scenario not found', {
99
- scenario: scenarioName
100
- })
101
- )
102
- }
103
-
104
- if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
105
- const { category, privilege } = scenario.privilege || {}
106
- throw new Error(
107
- `Unauthorized! ${
108
- category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'
109
- } required`
110
- )
111
- }
112
-
113
- instanceName = instanceName || scenarioName
114
- return await ScenarioEngine.load(instanceName, scenario, { domain, user, lng, variables })
34
+ return await controllerStartScenario(instanceName, scenarioName, variables, context)
115
35
  }
116
36
 
117
37
  @Mutation(returns => ScenarioInstance, { nullable: true, description: 'To start new scenario instance' })
118
- async stopScenario(
119
- @Arg('instanceName', { nullable: true }) instanceName: string,
120
- @Ctx() context: ResolverContext
121
- ): Promise<ScenarioInstance | undefined> {
122
- const { domain, user, unsafeIP, prohibitedPrivileges } = context.state
123
-
124
- debug('stopScenario', instanceName)
125
-
126
- var scenarioInstance = ScenarioEngine.getScenarioInstance(domain, instanceName)
127
-
128
- if (!scenarioInstance) {
129
- debug('stopScenario', `ScenarioInstance(${instanceName}) Not Found.`)
130
- throw new Error(
131
- context.t('error.scenario instance not found', {
132
- instance: instanceName
133
- })
134
- )
135
- }
136
-
137
- var scenario = await findScenario(scenarioInstance.scenarioName, domain)
138
-
139
- if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
140
- const { category, privilege } = scenario.privilege || {}
141
- throw new Error(
142
- `Unauthorized! ${
143
- category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'
144
- } required`
145
- )
146
- }
147
-
148
- await ScenarioEngine.unload(domain, instanceName)
149
-
150
- return scenarioInstance
38
+ async stopScenario(@Arg('instanceName', { nullable: true }) instanceName: string, @Ctx() context: ResolverContext): Promise<ScenarioInstance | undefined> {
39
+ return await controllerStopScenario(instanceName, context)
151
40
  }
152
41
  }
@@ -125,7 +125,7 @@ export class ScenarioInstance {
125
125
  timestamp: Date
126
126
 
127
127
  @Field({ nullable: true })
128
- private message: string
128
+ public message: string
129
129
 
130
130
  private steps: Step[]
131
131
  private rounds: number = 0
@@ -267,10 +267,7 @@ export class ScenarioInstance {
267
267
  this.context.logger.error(ex.message ? ex.message : ex)
268
268
 
269
269
  debug('failed to run ', `[ Domain: ${domain.name}, Scenario: ${scenarioName} ]\n`, ex)
270
- this.setState(
271
- ScenarioInstanceStatus.HALTED,
272
- typeof message == 'object' ? JSON.stringify(message, null, 2) : message
273
- )
270
+ this.setState(ScenarioInstanceStatus.HALTED, typeof message == 'object' ? JSON.stringify(message, null, 2) : message)
274
271
 
275
272
  throw ex
276
273
  }
@@ -376,9 +373,9 @@ export class ScenarioInstance {
376
373
  return
377
374
  }
378
375
 
379
- this.message = `${this.instanceName}:[state changed] ${ScenarioInstanceStatus[this.getState()]} => ${
380
- ScenarioInstanceStatus[state]
381
- }${message ? ' caused by ' + util.inspect(message, false, 2, true) : ''}`
376
+ this.message = `${this.instanceName}:[state changed] ${ScenarioInstanceStatus[this.getState()]} => ${ScenarioInstanceStatus[state]}${
377
+ message ? ' caused by ' + util.inspect(message, false, 2, true) : ''
378
+ }`
382
379
 
383
380
  this.context.state = state
384
381
 
@@ -421,6 +418,12 @@ export class ScenarioInstance {
421
418
  if (this.disposer) {
422
419
  await this.disposer.call(this)
423
420
  }
421
+
422
+ // {{ CHECKPOINT 본 인스턴스를 위해서 생성된 logger를 닫는다.
423
+ if (this.context?.logger) {
424
+ this.context.logger.close()
425
+ }
426
+ // }}
424
427
  }
425
428
 
426
429
  async process(step, context): Promise<{ next: string; state: ScenarioInstanceStatus; data: object }> {