Did anyone manage to run the step function within ...
# help
m
Did anyone manage to run the step function within the SST with typescript lambdas? I have implemented the PoolJob example by adding to the stack the following:
Copy code
const submitLambda = new Function(this, "SubmitLambda", {
  handler: "src/placeOrder/lambdas.submit",
});;
const getStatusLambda = new Function(this, "getStatusLambda", {
  handler: "src/placeOrder/lambdas.getStatus",
});;;


const submitJob = new tasks.LambdaInvoke(this, 'Submit Job', {
  lambdaFunction: submitLambda,
  // Lambda's result is in the attribute `Payload`
  outputPath: '$.Payload',
});

const waitX = new sfn.Wait(this, 'Wait X Seconds', {
  time: sfn.WaitTime.secondsPath('$.waitSeconds'),
});

const getStatus = new tasks.LambdaInvoke(this, 'Get Job Status', {
  lambdaFunction: getStatusLambda,
  // Pass just the field named "guid" into the Lambda, put the
  // Lambda's result in a field called "status" in the response
  inputPath: '$.guid',
  outputPath: '$.Payload',
});

const jobFailed = new sfn.Fail(this, 'Job Failed', {
  cause: 'AWS Batch Job Failed',
  error: 'DescribeJob returned FAILED',
});

const finalStatus = new tasks.LambdaInvoke(this, 'Get Final Job Status', {
  lambdaFunction: getStatusLambda,
  // Use "guid" field as input
  inputPath: '$.guid',
  outputPath: '$.Payload',
});

const definition = submitJob
    .next(waitX)
    .next(getStatus)
    .next(new sfn.Choice(this, 'Job Complete?')
    // Look at the "status" field
        .when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed)
        .when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus)
        .otherwise(waitX));

new sfn.StateMachine(this, 'StateMachine', {
  definition,
  timeout: Duration.minutes(5),
});
it does work, the stateMachine is being deployed to the AWS, i can run it (from AWS) and I see that the exection is correct only if the guid is numeric. those are my lambdas:
Copy code
export async function submit(event:any) {
  console.log("sumbit Lambda", event);
  const response = {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    waitSeconds: 1,
    guid: '3',
  };
  return response;
}

export async function getStatus(event:any) {

  const status = Math.random() >= 0.5 ? "FAILED" : "SUCCEEDED";
  console.log("getStatys Lambda", event, status);
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    status: status,
    guid: '3',
  };
}
and it does work. but if I change the submit lambda to:
Copy code
export async function submit(event:any) {
  console.log("sumbit Lambda", event);
  const response = {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    waitSeconds: 1,
    guid: 'abc',
  };
  return response;
}
the difference is guid: 'abc' vs guid: '3'. I get the following error on the getStatus state
{
"error": "Lambda.InvalidRequestContentException",
"cause": "Could not parse request body into json: Could not parse payload into json: Unrecognized token 'abc': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (byte[])\"abc\"; line: 1, column: 4] (Service: AWSLambda; Status Code: 400; Error Code: InvalidRequestContentException; Request ID: 7291da41-1c65-441b-8778-c87602b922cf; Proxy: null)"
}
any idea what may be wrong? I tried different ways of forming the string and all failed which drives me crazy. :D
b
I’ve implemented lambdas and C# and Typescript but I’ve always used the async method (with the task token). From memory, your lambda responses going back to the state machine need to be converted to strings (using
JSON.stringify(repsonse)
. Not sure why the string format of your
guid
field makes a difference, but maybe it’s falling over further up the stack internally. Try the stringify method, if it still breaks I’m not quite sure what to suggest. EDIT: Looking at the docs this seems like a standard thing: https://docs.aws.amazon.com/step-functions/latest/dg/concepts-state-machine-data.html#concepts-state-machine-data-state-input-output
m
@Brinsley if you mean this:
Copy code
export async function submit(event:any) {
  const response = JSON.stringify({
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    waitSeconds: 1,
    guid: 'abc',
  });
  return response;
}
then it does not make any change, still failing
b
return JSON.stringify(response)
is what I meant. You need the string returned by the JSON method.
Ignore that, misread your code.
f
Just to chime in guys, I think
guid
needs to return a JSON object?
Looking at the error, it suggests that
guid
was
Unrecognized token 'abc': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false'
b
I thought that initially but then figured the `body\ field would have fallen over first?
f
It seems step function was able to parse out
abc
, so maybe the overall response format is okay.
It might be that @Marcin M is using
guid
as an inputPath and step functions want it to be a JSON
Copy code
inputPath: '$.guid',
m
which would be weird becasue it works when guid is set to '3', and also the when condition evaluated on 'statutus' returned by the other lambda is working...
well, it does work with JSON object, but makes me think it is the bug. I will explain why: my lambdas (which now work)
Copy code
export async function submit(event:any) {
  const status = Math.random() >= 0.5 ? "FAILED" : "SUCCEEDED";
  const response = {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    waitSeconds: 1,
    guid: { "test" : "abc"},
  };
  return response;
}

export async function getStatus(event:any) {

  const status = Math.random() >= 0.5 ? "FAILED" : "SUCCEEDED";
  console.log("getStatys Lambda", event, status);
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, World! Are we running locally: ${!!process.env.IS_LOCAL}`,
    status: status,
    guid: '3',
  };
}
plus important snippets from the statemachine definition:
Copy code
const submitJob = new tasks.LambdaInvoke(this, 'Submit Job', {
  lambdaFunction: submitLambda,
  // Lambda's result is in the attribute `Payload`
  outputPath: '$.Payload',
});

//..


const getStatus = new tasks.LambdaInvoke(this, 'Get Job Status', {
  lambdaFunction: getStatusLambda,
  // Pass just the field named "guid" into the Lambda, put the
  // Lambda's result in a field called "status" in the response
  inputPath: '$.guid',
  outputPath: '$.Payload',
});
// ...
const finalStatus = new tasks.LambdaInvoke(this, 'Get Final Job Status', {
  lambdaFunction: getStatusLambda,
  // Use "guid" field as input
  inputPath: '$.guid',
  outputPath: '$.Payload',
});
plus the diagram for more clarity
f
Maybe step functions was treating
'3'
as an integer instead of a string?
m
@Frank could be, but what is the diff then? it does expect
JSON String, Number, Array, Object or token 'null', 'true' or 'false'
so, how to form just a string? 😄
I tried to return
guid: true
and then got
{
"error": "States.Runtime",
"cause": "An error occurred while executing the state 'Get Job Status' (entered at the event id #9). The Parameters '{\"FunctionName\":\"arn:aws:lambda:eu-west-1:259471222605:function:e974037-sst-tamos-demo-my--getStatusLambda37FF10F0-nVagaLuMYybZ\",\"Payload\":true}' could not be used to start the Task: [The value for the field 'Payload' must be a STRING]"
}
f
Oh I see.. seems like some type restriction on input path.. I don’t know step functions enough to explain this lol
m
even more odd behaviors: works with: [], string with number value ('3'), object does not work with: true, null, number (3 without quotations), false
easy to overcome with the object, let's leave that for future reference. thanks for your help guys