@mbc-cqrs-serverless/cli 0.1.73-beta.0 → 0.1.75-beta.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbc-cqrs-serverless/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.75-beta.0",
|
|
4
4
|
"description": "a CLI to get started with MBC CQRS serverless framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mbc",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"@faker-js/faker": "^8.3.1",
|
|
59
59
|
"copyfiles": "^2.4.1"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "a9c91c6ab9ca15188d7b7075989e90048248721c"
|
|
62
62
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IChainable,
|
|
3
|
+
JsonPath,
|
|
4
|
+
ProcessorConfig,
|
|
5
|
+
ProcessorMode,
|
|
6
|
+
Map as SfnMap,
|
|
7
|
+
} from 'aws-cdk-lib/aws-stepfunctions'
|
|
8
|
+
|
|
9
|
+
export type DistributedMapS3Parameter =
|
|
10
|
+
| {
|
|
11
|
+
readonly 'Bucket.$': string
|
|
12
|
+
readonly 'Key.$': string
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
readonly Bucket: JsonPath | string
|
|
16
|
+
readonly Key: JsonPath | string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DistributedMapItemReader {
|
|
20
|
+
readonly Resource:
|
|
21
|
+
| 'arn:aws:states:::s3:getObject'
|
|
22
|
+
| 'arn:aws:states:::s3:listObjectsV2'
|
|
23
|
+
readonly ReaderConfig: {
|
|
24
|
+
readonly InputType: 'CSV' | 'JSON' | 'MANIFEST'
|
|
25
|
+
readonly CSVHeaderLocation?: 'FIRST_ROW' | 'GIVEN'
|
|
26
|
+
readonly CSVHeaders?: string[]
|
|
27
|
+
readonly MaxItems?: number
|
|
28
|
+
}
|
|
29
|
+
readonly Parameters: DistributedMapS3Parameter
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface DistributedMapResultWriter {
|
|
33
|
+
readonly Resource: 'arn:aws:states:::s3:putObject'
|
|
34
|
+
readonly Parameters: DistributedMapS3Parameter
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DistributedMapItemBatcher {
|
|
38
|
+
readonly MaxItemsPerBatch?: number
|
|
39
|
+
readonly MaxItemsPerBatchPath?: string
|
|
40
|
+
readonly MaxInputBytesPerBatch?: number
|
|
41
|
+
readonly MaxInputBytesPerBatchPath?: number
|
|
42
|
+
readonly BatchInput?: Readonly<Record<string, JsonPath | string>>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class DistributedMap extends SfnMap {
|
|
46
|
+
public itemReader?: DistributedMapItemReader
|
|
47
|
+
public resultWriter?: DistributedMapResultWriter
|
|
48
|
+
public itemBatcher?: DistributedMapItemBatcher
|
|
49
|
+
declare public itemSelector?: Readonly<Record<string, JsonPath | string>>
|
|
50
|
+
public label?: string
|
|
51
|
+
|
|
52
|
+
public override toStateJson(): object {
|
|
53
|
+
const mapStateJson = super.toStateJson()
|
|
54
|
+
return {
|
|
55
|
+
...mapStateJson,
|
|
56
|
+
ItemReader: this.itemReader,
|
|
57
|
+
ResultWriter: this.resultWriter,
|
|
58
|
+
ItemBatcher: this.itemBatcher,
|
|
59
|
+
ItemSelector: this.itemSelector,
|
|
60
|
+
Label: this.label,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public itemProcessor(
|
|
65
|
+
processor: IChainable,
|
|
66
|
+
config: ProcessorConfig = {},
|
|
67
|
+
): DistributedMap {
|
|
68
|
+
super.itemProcessor(processor, {
|
|
69
|
+
...config,
|
|
70
|
+
mode: ProcessorMode.DISTRIBUTED,
|
|
71
|
+
})
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public setLabel(label: string): DistributedMap {
|
|
76
|
+
this.label = label
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public setItemSelector(
|
|
81
|
+
itemSelector: Readonly<Record<string, JsonPath | string>>,
|
|
82
|
+
): DistributedMap {
|
|
83
|
+
this.itemSelector = itemSelector
|
|
84
|
+
return this
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public setItemBatcher(
|
|
88
|
+
itemBatcher: DistributedMapItemBatcher,
|
|
89
|
+
): DistributedMap {
|
|
90
|
+
this.itemBatcher = itemBatcher
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public setResultWriter(
|
|
95
|
+
resultWriter: DistributedMapResultWriter,
|
|
96
|
+
): DistributedMap {
|
|
97
|
+
this.resultWriter = resultWriter
|
|
98
|
+
return this
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public setItemReader(itemReader: DistributedMapItemReader): DistributedMap {
|
|
102
|
+
this.itemReader = itemReader
|
|
103
|
+
return this
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '../config'
|
|
21
21
|
import { Config } from '../config/type'
|
|
22
22
|
import { buildApp } from './build-app'
|
|
23
|
+
import { DistributedMap } from './distributed-map'
|
|
23
24
|
|
|
24
25
|
export interface InfraStackProps extends cdk.StackProps {
|
|
25
26
|
config: Config
|
|
@@ -115,6 +116,10 @@ export class InfraStack extends cdk.Stack {
|
|
|
115
116
|
},
|
|
116
117
|
})
|
|
117
118
|
|
|
119
|
+
const importActionSqs = new cdk.aws_sqs.Queue(this, 'import-action-sqs', {
|
|
120
|
+
queueName: prefix + 'import-action-queue',
|
|
121
|
+
})
|
|
122
|
+
|
|
118
123
|
const subTaskStatusSqs = new cdk.aws_sqs.Queue(
|
|
119
124
|
this,
|
|
120
125
|
'sub-task-status-sqs',
|
|
@@ -163,6 +168,17 @@ export class InfraStack extends cdk.Stack {
|
|
|
163
168
|
},
|
|
164
169
|
}),
|
|
165
170
|
)
|
|
171
|
+
|
|
172
|
+
mainSns.addSubscription(
|
|
173
|
+
new cdk.aws_sns_subscriptions.SqsSubscription(importActionSqs, {
|
|
174
|
+
rawMessageDelivery: true,
|
|
175
|
+
filterPolicy: {
|
|
176
|
+
action: cdk.aws_sns.SubscriptionFilter.stringFilter({
|
|
177
|
+
allowlist: ['import-execute'],
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
}),
|
|
181
|
+
)
|
|
166
182
|
// host zone
|
|
167
183
|
const hostedZone = cdk.aws_route53.HostedZone.fromHostedZoneAttributes(
|
|
168
184
|
this,
|
|
@@ -353,6 +369,18 @@ export class InfraStack extends cdk.Stack {
|
|
|
353
369
|
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME,
|
|
354
370
|
})
|
|
355
371
|
|
|
372
|
+
const importCsvStateMachineName = prefix + 'import-csv-handler'
|
|
373
|
+
|
|
374
|
+
const importCsvSfnArn = cdk.Arn.format({
|
|
375
|
+
partition: 'aws',
|
|
376
|
+
region: this.region,
|
|
377
|
+
account: this.account,
|
|
378
|
+
service: 'states',
|
|
379
|
+
resource: 'stateMachine',
|
|
380
|
+
resourceName: importCsvStateMachineName,
|
|
381
|
+
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME,
|
|
382
|
+
})
|
|
383
|
+
|
|
356
384
|
// Lambda api ( arm64 )
|
|
357
385
|
const execEnv = {
|
|
358
386
|
NODE_OPTIONS: '--enable-source-maps',
|
|
@@ -365,6 +393,7 @@ export class InfraStack extends cdk.Stack {
|
|
|
365
393
|
S3_BUCKET_NAME: ddbBucket.bucketName,
|
|
366
394
|
SFN_COMMAND_ARN: commandSfnArn,
|
|
367
395
|
SFN_TASK_ARN: taskSfnArn,
|
|
396
|
+
SFN_IMPORT_CSV_ARN: importCsvSfnArn,
|
|
368
397
|
SNS_TOPIC_ARN: mainSns.topicArn,
|
|
369
398
|
SNS_ALARM_TOPIC_ARN: alarmSns.topicArn,
|
|
370
399
|
COGNITO_USER_POOL_ID: userPool.userPoolId,
|
|
@@ -851,6 +880,65 @@ export class InfraStack extends cdk.Stack {
|
|
|
851
880
|
},
|
|
852
881
|
)
|
|
853
882
|
|
|
883
|
+
// Csv import
|
|
884
|
+
const csvRowsHandlerState = lambdaInvoke(
|
|
885
|
+
'csv_rows_handler',
|
|
886
|
+
null,
|
|
887
|
+
cdk.aws_stepfunctions.IntegrationPattern.REQUEST_RESPONSE,
|
|
888
|
+
)
|
|
889
|
+
|
|
890
|
+
const sfnImportCsvDefinition = new DistributedMap(this, 'import-csv', {
|
|
891
|
+
maxConcurrency: 50,
|
|
892
|
+
})
|
|
893
|
+
.setLabel('import-csv')
|
|
894
|
+
.setItemReader({
|
|
895
|
+
Resource: 'arn:aws:states:::s3:getObject',
|
|
896
|
+
ReaderConfig: {
|
|
897
|
+
InputType: 'CSV',
|
|
898
|
+
CSVHeaderLocation: 'FIRST_ROW',
|
|
899
|
+
},
|
|
900
|
+
Parameters: {
|
|
901
|
+
'Bucket.$': '$.bucket',
|
|
902
|
+
'Key.$': '$.key',
|
|
903
|
+
},
|
|
904
|
+
})
|
|
905
|
+
.setItemBatcher({
|
|
906
|
+
MaxInputBytesPerBatch: 10,
|
|
907
|
+
BatchInput: {
|
|
908
|
+
'Attributes.$': '$',
|
|
909
|
+
},
|
|
910
|
+
})
|
|
911
|
+
.itemProcessor(csvRowsHandlerState, {
|
|
912
|
+
executionType: cdk.aws_stepfunctions.ProcessorType.EXPRESS,
|
|
913
|
+
})
|
|
914
|
+
|
|
915
|
+
const sfnImportCsvLogGroup = new cdk.aws_logs.LogGroup(
|
|
916
|
+
this,
|
|
917
|
+
'import-csv-handler-sfn-log',
|
|
918
|
+
{
|
|
919
|
+
logGroupName: `/aws/vendedlogs/states/${prefix}-import-csv-handler-state-machine-logs`, // Specify a log group name
|
|
920
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY, // Policy for log group removal
|
|
921
|
+
retention: cdk.aws_logs.RetentionDays.SIX_MONTHS,
|
|
922
|
+
},
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
const importCsvStateMachine = new cdk.aws_stepfunctions.StateMachine(
|
|
926
|
+
this,
|
|
927
|
+
'import-csv-state-machine',
|
|
928
|
+
{
|
|
929
|
+
stateMachineName: importCsvStateMachineName,
|
|
930
|
+
comment: 'A state machine for import-csv module handler',
|
|
931
|
+
definitionBody: cdk.aws_stepfunctions.DefinitionBody.fromChainable(
|
|
932
|
+
sfnImportCsvDefinition,
|
|
933
|
+
),
|
|
934
|
+
tracingEnabled: true,
|
|
935
|
+
logs: {
|
|
936
|
+
destination: sfnImportCsvLogGroup,
|
|
937
|
+
level: cdk.aws_stepfunctions.LogLevel.ALL, // Log level (ALL, ERROR, or FATAL)
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
)
|
|
941
|
+
|
|
854
942
|
// add event sources to lambda event
|
|
855
943
|
lambdaApi.addEventSource(
|
|
856
944
|
new cdk.aws_lambda_event_sources.SqsEventSource(taskSqs, {
|
|
@@ -867,8 +955,13 @@ export class InfraStack extends cdk.Stack {
|
|
|
867
955
|
batchSize: 1,
|
|
868
956
|
}),
|
|
869
957
|
)
|
|
958
|
+
lambdaApi.addEventSource(
|
|
959
|
+
new cdk.aws_lambda_event_sources.SqsEventSource(importActionSqs, {
|
|
960
|
+
batchSize: 1,
|
|
961
|
+
}),
|
|
962
|
+
)
|
|
870
963
|
// dynamodb event source
|
|
871
|
-
const tableNames = ['tasks', 'sample-command']
|
|
964
|
+
const tableNames = ['tasks', 'sample-command', 'import_tmp']
|
|
872
965
|
for (const tableName of tableNames) {
|
|
873
966
|
const tableDesc = new cdk.custom_resources.AwsCustomResource(
|
|
874
967
|
this,
|
|
@@ -926,6 +1019,17 @@ export class InfraStack extends cdk.Stack {
|
|
|
926
1019
|
'cognito-idp:AdminUpdateUserAttributes',
|
|
927
1020
|
)
|
|
928
1021
|
ddbBucket.grantReadWrite(lambdaApi)
|
|
1022
|
+
ddbBucket.grantRead(importCsvStateMachine)
|
|
1023
|
+
importCsvStateMachine.role?.attachInlinePolicy(
|
|
1024
|
+
new cdk.aws_iam.Policy(this, 'csv-import-map-policy', {
|
|
1025
|
+
statements: [
|
|
1026
|
+
new cdk.aws_iam.PolicyStatement({
|
|
1027
|
+
actions: ['states:StartExecution'],
|
|
1028
|
+
resources: [importCsvSfnArn],
|
|
1029
|
+
}),
|
|
1030
|
+
],
|
|
1031
|
+
}),
|
|
1032
|
+
)
|
|
929
1033
|
publicBucket.grantReadWrite(lambdaApi)
|
|
930
1034
|
mainSns.grantPublish(lambdaApi)
|
|
931
1035
|
alarmSns.grantPublish(lambdaApi)
|
|
@@ -973,6 +1077,11 @@ export class InfraStack extends cdk.Stack {
|
|
|
973
1077
|
resources: [taskSfnArn], // Access to all resources
|
|
974
1078
|
})
|
|
975
1079
|
|
|
1080
|
+
const importCsvSfnPolicy = new cdk.aws_iam.PolicyStatement({
|
|
1081
|
+
actions: ['states:*'],
|
|
1082
|
+
resources: [importCsvSfnArn], // Access to all resources
|
|
1083
|
+
})
|
|
1084
|
+
|
|
976
1085
|
// Attach the policy to the Lambda function's execution role
|
|
977
1086
|
lambdaApi.role?.attachInlinePolicy(
|
|
978
1087
|
new cdk.aws_iam.Policy(this, 'lambda-event-sfn-policy', {
|
|
@@ -991,6 +1100,16 @@ export class InfraStack extends cdk.Stack {
|
|
|
991
1100
|
}),
|
|
992
1101
|
)
|
|
993
1102
|
|
|
1103
|
+
lambdaApi.role?.attachInlinePolicy(
|
|
1104
|
+
new cdk.aws_iam.Policy(
|
|
1105
|
+
this,
|
|
1106
|
+
'lambda-import-csv-sfn-step-function-policy',
|
|
1107
|
+
{
|
|
1108
|
+
statements: [importCsvSfnPolicy.copy()],
|
|
1109
|
+
},
|
|
1110
|
+
),
|
|
1111
|
+
)
|
|
1112
|
+
|
|
994
1113
|
// Attach the policy to the Lambda function's execution role
|
|
995
1114
|
lambdaApi.role?.attachInlinePolicy(
|
|
996
1115
|
new cdk.aws_iam.Policy(this, 'lambda-ses-policy', {
|
|
@@ -45,6 +45,11 @@ custom:
|
|
|
45
45
|
rawMessageDelivery: 'true'
|
|
46
46
|
filterPolicy: { 'action': ['sub-task-status'] }
|
|
47
47
|
queue: http://localhost:9324/101010101010/sub-task-status-queue
|
|
48
|
+
- topic:
|
|
49
|
+
topicName: CqrsSnsTopic
|
|
50
|
+
rawMessageDelivery: 'true'
|
|
51
|
+
filterPolicy: { 'action': ['import-execute'] }
|
|
52
|
+
queue: http://localhost:9324/101010101010/import-action-queue
|
|
48
53
|
- topic:
|
|
49
54
|
topicName: AlarmSnsTopic
|
|
50
55
|
rawMessageDelivery: 'true'
|
|
@@ -157,6 +162,11 @@ functions:
|
|
|
157
162
|
Fn::GetAtt:
|
|
158
163
|
- NotificationQueue
|
|
159
164
|
- Arn
|
|
165
|
+
- sqs:
|
|
166
|
+
arn:
|
|
167
|
+
Fn::GetAtt:
|
|
168
|
+
- ImportActionQueue
|
|
169
|
+
- Arn
|
|
160
170
|
- stream:
|
|
161
171
|
type: dynamodb
|
|
162
172
|
maximumRetryAttempts: 10
|
|
@@ -169,6 +179,13 @@ functions:
|
|
|
169
179
|
arn: ${env:LOCAL_DDB_TASKS_STREAM}
|
|
170
180
|
filterPatterns:
|
|
171
181
|
- eventName: [INSERT]
|
|
182
|
+
- stream:
|
|
183
|
+
type: dynamodb
|
|
184
|
+
maximumRetryAttempts: 10
|
|
185
|
+
arn: ${env:LOCAL_DDB_IMPORT_TMP_STREAM}
|
|
186
|
+
filterPatterns:
|
|
187
|
+
- eventName:
|
|
188
|
+
- INSERT
|
|
172
189
|
|
|
173
190
|
stepFunctions:
|
|
174
191
|
# https://goessner.net/articles/JsonPath/index.html
|
|
@@ -366,6 +383,48 @@ stepFunctions:
|
|
|
366
383
|
End: true
|
|
367
384
|
End: true
|
|
368
385
|
# MaxConcurrency: 2
|
|
386
|
+
import-csv:
|
|
387
|
+
name: import-csv
|
|
388
|
+
definition:
|
|
389
|
+
Comment: import csv data
|
|
390
|
+
StartAt: csv_loader
|
|
391
|
+
States:
|
|
392
|
+
csv_loader:
|
|
393
|
+
Type: Task
|
|
394
|
+
Resource: arn:aws:states:::lambda:invoke
|
|
395
|
+
Parameters:
|
|
396
|
+
FunctionName: arn:aws:lambda:ap-northeast-1:101010101010:function:serverless-example-dev-main
|
|
397
|
+
Payload:
|
|
398
|
+
input.$: $
|
|
399
|
+
context.$: $$
|
|
400
|
+
Retry:
|
|
401
|
+
- ErrorEquals:
|
|
402
|
+
- Lambda.ServiceException
|
|
403
|
+
- Lambda.AWSLambdaException
|
|
404
|
+
- Lambda.SdkClientException
|
|
405
|
+
IntervalSeconds: 2
|
|
406
|
+
MaxAttempts: 5
|
|
407
|
+
BackoffRate: 2
|
|
408
|
+
OutputPath: $.Payload[0][0]
|
|
409
|
+
Next: read_csv
|
|
410
|
+
read_csv:
|
|
411
|
+
Type: Task
|
|
412
|
+
Resource: arn:aws:states:::lambda:invoke
|
|
413
|
+
Parameters:
|
|
414
|
+
FunctionName: arn:aws:lambda:ap-northeast-1:101010101010:function:serverless-example-dev-main
|
|
415
|
+
Payload:
|
|
416
|
+
input.$: $
|
|
417
|
+
context.$: $$
|
|
418
|
+
Retry:
|
|
419
|
+
- ErrorEquals:
|
|
420
|
+
- Lambda.ServiceException
|
|
421
|
+
- Lambda.AWSLambdaException
|
|
422
|
+
- Lambda.SdkClientException
|
|
423
|
+
IntervalSeconds: 2
|
|
424
|
+
MaxAttempts: 5
|
|
425
|
+
BackoffRate: 2
|
|
426
|
+
OutputPath: $.Payload[0][0]
|
|
427
|
+
End: true
|
|
369
428
|
resources:
|
|
370
429
|
Resources:
|
|
371
430
|
TaskActionQueue:
|
|
@@ -380,3 +439,7 @@ resources:
|
|
|
380
439
|
Type: AWS::SQS::Queue
|
|
381
440
|
Properties:
|
|
382
441
|
QueueName: notification-queue
|
|
442
|
+
ImportActionQueue:
|
|
443
|
+
Type: AWS::SQS::Queue
|
|
444
|
+
Properties:
|
|
445
|
+
QueueName: import-action-queue
|