Skip to content

Commit

Permalink
tz/297/aws step functions (#340)
Browse files Browse the repository at this point in the history
* Add feature for Step Functions.

* AWS function for wrapping the step function

* Added docs and examples for how to run step functions and check on them

* Update package.json

* Updated yarn file

* tz/297/aws-step-functions
* fix linting

---------
  • Loading branch information
tzinckgraf authored Jun 25, 2024
1 parent 856c36e commit 8a01dc5
Show file tree
Hide file tree
Showing 8 changed files with 1,109 additions and 1 deletion.
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@aws-sdk/client-s3": "^3.472.0",
"@aws-sdk/client-secrets-manager": "^3.478.0",
"@aws-sdk/client-ses": "^3.470.0",
"@aws-sdk/client-sfn": "^3.470.0",
"@aws-sdk/client-sqs": "^3.470.0",
"@aws-sdk/client-ssm": "^3.462.0",
"@aws-sdk/rds-signer": "^3.462.0",
Expand Down
45 changes: 45 additions & 0 deletions api/src/lib/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import {
PutObjectCommandInput,
S3Client,
} from '@aws-sdk/client-s3'
import {
SFNClient,
StartExecutionCommand,
StartExecutionCommandOutput
} from '@aws-sdk/client-sfn';
import {
ReceiveMessageCommand,
SendMessageCommand,
Expand Down Expand Up @@ -165,11 +170,51 @@ async function receiveSqsMessage(queueUrl: string) {
)
}

/**
* Create a step function execution.
* AWS docs can be found at the following:
* https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sfn/command/StartExecutionCommand/
*
* For localstack docs, see https://docs.localstack.cloud/user-guide/aws/stepfunctions/
*
* @param arn
* @param name
* @param input
* @param traceHeader
*/
async function startStepFunctionExecution(
arn: string,
name?: string,
input?: any,
traceHeader?: string,
): Promise<StartExecutionCommandOutput> {
let client: SFNClient;
const command = new StartExecutionCommand(
{
stateMachineArn: arn,
name,
input: input ?? "{}",
traceHeader,
}
);
if (process.env.LOCALSTACK_HOSTNAME) {
console.log('------------ USING LOCALSTACK FOR SFN ------------')
const endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:${
process.env.EDGE_PORT || 4566
}`
client = new SFNClient({ endpoint, region: process.env.AWS_DEFAULT_REGION })
} else {
client = new SFNClient()
}
return await client.send(command)
}

export default {
sendPutObjectToS3Bucket,
sendHeadObjectToS3Bucket,
getSignedUrl,
sendSqsMessage,
receiveSqsMessage,
getS3Client,
startStepFunctionExecution,
}
2 changes: 2 additions & 0 deletions localstack/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ services:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
- "./entrypoint/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh"
- "../scripts/function.zip:/tmp/function.zip"
- "../scripts/function_py.zip:/tmp/function_py.zip"
52 changes: 52 additions & 0 deletions localstack/entrypoint/init-aws.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,55 @@ done

awslocal s3api create-bucket --bucket cpf-reporter --region us-west-2 --create-bucket-configuration '{"LocationConstraint": "us-west-2"}'

awslocal lambda create-function \
--function-name localstack-js-lambda-example \
--runtime nodejs16.x \
--zip-file fileb:///tmp/function.zip \
--handler index.handler \
--role arn:aws:iam::000000000000:role/lambda-role

awslocal lambda create-function \
--function-name localstack-py-lambda-example \
--runtime python3.9 \
--zip-file fileb:///tmp/function_py.zip \
--handler sample_lambda.lambda_handler \
--role arn:aws:iam::000000000000:role/lambda-role

#
# The js lambdas can be a bit tricky for inputs,
# so instead we use two python lambdas strung together
#
awslocal stepfunctions create-state-machine \
--name "run-sample-functions" \
--definition '{
"Comment": "Invoke Two Lambda Functions",
"StartAt": "Lambda1",
"States": {
"Lambda1": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "localstack-py-lambda-example",
"Payload": {
"input.$": "$"
}
},
"OutputPath": "$.Payload",
"Next": "InvokeLambda"
},
"InvokeLambda": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "localstack-py-lambda-example",
"Payload": {
"input.$": "$"
}
},
"OutputPath": "$.Payload",
"End": true
}
}
}' \
--role-arn "arn:aws:iam::000000000000:role/stepfunctions-role"

23 changes: 23 additions & 0 deletions scripts/awsTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import aws from 'api/src/lib/aws'

export default async ({ args }) => {
/*
Example running:
yarn redwood exec awsTest --input '{"var1":"val1"}' --arn arn:aws:states:us-west-2:000000000000:stateMachine:run-sample-functions --name "testing"
Using the executionArn from above in the next command.
The arn should looks something like
arn:aws:states:us-west-2:000000000000:execution:run-sample-functions:8110adbe-6807-443f-82ba-6acf9bc527ea
To check the output, do the following:
docker exec -it cpf-reporter-localstack-main /bin/bash
awslocal stepfunctions describe-execution --execution-arn [executionArn from above]
*/

console.log(':: Executing script with args ::')
console.log(`Received following arguments: ${Object.keys(args)}`)

const result = await aws.startStepFunctionExecution(args.arn, args.name, args.input, '');
console.log(result);
console.log(result.body);
};
11 changes: 11 additions & 0 deletions scripts/sample_lambda.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* To build this, zip it using zip scripts/function.zip scripts/sample_lambda.js
*/
exports.handler = async (event) => {
//console.log("EVENT: " + JSON.stringify(event));
const response = {
statusCode: 200,
body: "Hello from my LocalStack Lambda function!\n" + event.input,
};
return response;
};
6 changes: 6 additions & 0 deletions scripts/sample_lambda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
To build this, zip it using zip scripts/function.zip scripts/sample_lambda.py
"""
def lambda_handler(event, context):
print(event)
return {k: f"{v}_sample" for k, v in event["input"].items()}
Loading

0 comments on commit 8a01dc5

Please sign in to comment.