I am using aws Step Functions to manage a workflow. I am using Fail states to handle errors within the workflow. I would like to propagate some of the json from the Step Function workflow so that a user can easily identify the source of their error. So for example, if the json input to a Fail state looked like this:
{
"error": "some error text",
"other_stuff": {...}
}
Then I would like to pull the source of the error. I have set up my Fail state like so:
FailState:
Type: Fail
Cause: States.Format($.error)
Error: Failure Here
However, this simply produces the literal string States.Format($.error) as the Cause for the Fail state. How can I use aws states language and the Fail state to show the actual error as a part of the output of the Fail state? Any solution that can successfully propagate the error text from Step Input to Step Output for the Fail state would be sufficient to solve this problem.
If anyone else stumbles on this question, I contacted AWS support and this is what they told me:
"The ‘Cause’ and ‘Error’ fields in this state only accept the string type values. This is why you are getting the literal string as a response. However, the good news is that, we already have an existing feature request, pending with Step Functions Development team, to implement a feature for sending JSON Path(like $.error) into the Fail state."
So for some reason AWS step functions does not allow you to pass dynamic error messages. They did offer some workarounds such as changing the failure state to success and propagating the error message that way, or creating an sns topic in the case of statemachine failure to post to. I personally just updated the status polling API to grab the state at index [-2] to propagate the error to the user. In any case, to use this functionality currently some workaround should be employed, and hopefully AWS can get this feature out quickly.
I was able to achieve something close to a desired behavior by creating a "Fail-Me" Lambda that fails with an unhandled exception, dynamically choosing exception class based on the Error and Cause provided as its payload. If "Error" was a name of a built-in exception class it uses it, otherwise it creates its own class.
In State Machine, use an Invoke Lambda state calling this "Fail-Me" lambda with no retrier and no catcher.
import inspect, sys
# Expected payload (event), example:
# {
# "Error":"RuntimeError",
# "Cause":"No Cause"
# }
def lambda_handler(event, context):
ErrorType = event.get("Error") or ""
ErrorCause = event.get("Cause") or ""
if not ErrorType.isidentifier():
ErrorCause = "{}: {}".format(ErrorType, ErrorCause)
ErrorType = "OtherError"
DynamicExceptionClass = type(ErrorType, (BaseException,), {})
for name, obj in inspect.getmembers(sys.modules["builtins"]):
if inspect.isclass(obj) and issubclass (obj, BaseException):
if name==ErrorType: #ErrorType is an existing built-in exception - use it
raise obj(ErrorCause)
#Create our own dynamic class and raise it
DynamicExceptionClass = type(ErrorType, (BaseException,), {})
raise DynamicExceptionClass(ErrorCause)
I too want to use a JSON path in a Fail state to dynamically set the Cause and Error fields. In my case, I have a known set of errors so for each one I created a separate Fail state. Each one of those fail states corresponded with a catch object where Next is set to the appropriate fail state.
{
"TaskState": {
"Type": "Task",
...
"Catch": [
{
"ErrorEquals": ["ErrorA"],
"Next": "FailureA"
},
{
"ErrorEquals": ["ErrorB"],
"Next": "FailureB"
}
]
},
"FailureA": {
"Type": "Fail",
"Error": "FailureA",
"Cause": "This failed because of A"
},
"FailureB": {
"Type": "Fail",
"Error": "FailureB",
"Cause": "This failed because of B"
}
}
Related
I've observed for failed multipart upload (like crash or stop in the middle), the partially uploaded object still exist in storage.
I want to configure lifecycle rules for these incomplete objects via either minio or S3 C++ SDk.
I want to configure something like
{
"ID": "bucket-lifecycle-incomplete-chunk-upload",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 1
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 1
}
},
My C++ code looks like the following:
Aws::S3::Model::AbortIncompleteMultipartUpload incomplete_upload_config;
incomplete_upload_config.SetDaysAfterInitiation(days);
Aws::S3::Model::NoncurrentVersionExpiration version_expire;
version_expire.SetNoncurrentDays(1);
auto status = Aws::S3::Model::ExpirationStatus::Enabled;
Aws::S3::Model::LifecycleRule rule;
rule.SetID("bucket-lifecycle-incomplete-chunk-upload");
rule.SetStatus(std::move(status));
rule.SetNoncurrentVersionExpiration(std::move(version_expire));
rule.SetAbortIncompleteMultipartUpload(std::move(incomplete_upload_config));
Aws::S3::Model::BucketLifecycleConfiguration bkt_config;
bkt_config.AddRules(std::move(rule));
Aws::S3::Model::PutBucketLifecycleConfigurationRequest config_req{};
config_req.SetBucket(bucket);
config_req.SetLifecycleConfiguration(std::move(bkt_config));
auto outcome = client->PutBucketLifecycleConfiguration(config_req);
And I get the following result:
Received HTTP return code: 400; Failed to update config for bucket <bucket-name> because MalformedXML: Unable to parse ExceptionName: MalformedXML Message:
The pain point for this error is: I cannot find which additional or missing fields lead to this error.
Background: I am building a cloud function using python to take a .csv uploaded to our bucket and upload its rows as entities into Datastore.
When trying to deploy the Python function, I got an error where the function would fail to deploy due to the following error code:
Build failed: {
"cacheStats": [{
"status": "MISS",
"hash": "SOME HASH",
"type": "docker_layer_cache",
"level": "global"
}, {
"status": "MISS",
"hash": "SOME HASH",
"type": "docker_layer_cache",
"level": "project"
}
]
}
To try to diagnose the problem, I attempted deploying a template Python function, and got the same error. (Code included below just in case)
def hello_world(request):
"""Responds to any HTTP request.
Args:
request (flask.Request): HTTP request object.
Returns:
The response text or any set of values that can be turned into a
Response object using
`make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
"""
request_json = request.get_json()
if request.args and 'message' in request.args:
return request.args.get('message')
elif request_json and 'message' in request_json:
return request_json['message']
else:
return f'Hello World!'
From my understanding of the error, it implies that there is an issue with the hashing to my project specifically, but it is not clear to me how to fix this, or what resulted in this error occurring.
https://cloud.google.com/functions/docs/troubleshooting has no information about an error of this type, and other errors that I have seen similar to this error are due to situations such as the entry function parameters being incorrect, which is not the case here.
Cloud functions are running as normal according to google (https://status.cloud.google.com/).
Is this a genuine problem on google's end? Or is there some setting that I am not aware of that would have caused this issue?
Update: Node.js functions are working fine, python functions still do not work. In addition, Go functions result in an error where the logs fail on build step #5 due to Token exchange failed for project: 'project-id'
I am currently using boto3 (the Amazon Web Services (AWS) SDK for Python) to create state machines, start executions and also in my workers to retrieve tasks and report their status (completed successfully or failed).
I have another service that needs to know the tasks' status and I would like to do so by retrieving it from AWS. I searched the available methods and it is only possible to get the status of a state machine/execution as a whole (RUNNING|SUCCEEDED|FAILED|TIMED_OUT|ABORTED).
There is also the get_execution_history method but each step is identified by an id numbered sequentially and there is no information about the task itself (only in the "stateEnteredEventDetails" event, where the name of the task is present, but the subsequentially events may not be related to it, so it is impossible to know if the task was successful or not).
Is it really not possible to retrieve the status of a specific task, or am I missing something?
Thank you!
I had the same problem, and it seems that step functions does not consider the states and tasks as entities, and therefore there is not an API to get info about them.
In order to get info about the task's status you need to parse the information in the execution history. In my case I first check the execution status:
import boto3
import json
client = boto3.client("stepfunctions")
response = client.describe_execution(
executionArn=EXECUTION_ARN
)
status = response["status"]
and if it is "FAILED" then I analyze the history and get the most relevant fields for my use case (for events of type "TaskFailed"):
response = client.get_execution_history(
executionArn=EXECUTION_ARN,
maxResults=1000
)
events = response["events"]
while response.get("nextToken"):
response = client.get_execution_history(
executionArn=EXECUTION_ARN,
maxResults=1000,
nextToken=response["nextToken"]
)
events += response["events"]
causes = [
json.loads(e["taskFailedEventDetails"]["cause"])
for e in events
if e["type"] == "TaskFailed"
]
return [
{
"ClusterArn": cause["ClusterArn"],
"Containers": [
{
"ContainerArn": container["ContainerArn"],
"Name": container["Name"],
"ExitCode": container["ExitCode"],
"Overrides": cause["Overrides"]["ContainerOverrides"][i]
}
for i, container in enumerate(cause["Containers"])
],
"TaskArn": cause["TaskArn"],
"StoppedReason": cause["StoppedReason"]
}
for cause in causes
]
I'm attempting to update an existing sink using the (Python) Google Stackdriver Logging API, and am getting an error that I can't track down.
The API explorer for the method in question is here, to which I'm supplying projects/my_project/sinks/my_sink_name as the sinkName, and the following for the Request Body:
{
"name": "audit_logs",
"destination": "bigquery.googleapis.com/projects/my_project/datasets/destination_dataset",
"filter": "resource.type=\"bigquery_resource\""
}
When submitting, I get the following error:
400 Bad Request
{
"error": {
"code": 400,
"message": "Request contains an invalid argument.",
"status": "INVALID_ARGUMENT"
}
}
...which doesn't specify which argument is invalid, and I have tried several variations without any success.
Additional info: this request is based on one generated by the Python API. I have also tried specifying the full path of the sink in name to no avail, which is what the Python API generates, which seems contrary to the documentation.
Can you try the UpdateSink with uniqueWriterIdentity set to true?
From https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/update:
"It is an error if the old value is true and the new value is set to false or defaulted to false."
I have created one AWS Lex bot and I am invoking one lambda function from that bot. When testing the lambda function I am getting proper response but at bot I am getting below error:
An error has occurred: Received invalid response from Lambda: Can not
construct instance of IntentResponse: no String-argument
constructor/factory method to deserialize from String value
('2017-06-22 10:23:55.0') at [Source: "2017-06-22 10:23:55.0"; line:
1, column: 1]
Not sure, what is wrong and where I am missing. Could anyone assist me please?
The solution to above problem is that we need to make sure response returned by lambda function, to be used at AWS lex chat bot should be in below format:
{
"sessionAttributes": {
"key1": "value1",
"key2": "value2"
...
},
"dialogAction": {
"type": "ElicitIntent, ElicitSlot, ConfirmIntent, Delegate, or Close",
Full structure based on the type field. See below for details.
}
}
By this, chat bot expectd DialogAction and corresponding elements in order to process the message i.e. IntentResponse.
Reference: http://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html
no String-argument constructor/factory method to deserialize from String value
You are getting this error because you must be passing string values in the response of lambda function. You have to pass a predefined json object blueprint in the response.
Because the communication between Lex and Lambda is not simple value passing like normal functions. Amazon Lex expects output from Lambda in a particular JSON format and data is sent to Lambda in a particular JSON. The examples are here: Lambda Function Input Event and Response Format.
And just copying and pasting the blueprint won't work because in some fields you have choose between some predefined values and in some fields you have to entry valid input.
For example in,
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled or Failed",
"message": {
"contentType": "PlainText or SSML",
"content": "Thanks, your pizza has been ordered."
}
}
you have assign a value "Fulfilled" or "Failed" to field 'fulfillmentState'. And same goes for 'contentType'.