Override field in the input before passing to the next state in AWS Step Function - amazon-web-services

Say I have 3 states, A -> B -> C. Let's assume inputs to A include a field called names which is of type List and each element contains two fields firstName and lastName. State B will process the inputs to A and and return a response called newLastName. If I want to override every element in names such that names[i].lastName = newLastName before passing this input to state C, is there an built-in syntax to achieve that? Thanks.

You control the events passed to the next task in a Step Function with three defintion attributes: ResultPath and OutputPath on leaving one task and InputPath on entering the next one.
You have to first understand how the event to the next task is crafted by a State Machine, and each of the 3 above parameters changes it.
You have to at least have Result Path. This is the key in the event that the output of your lambda will be placed under. so ResultPath="$.my_path" would result in a json object that has a top level key of my_path with the value equal to whatever is outputted from the lambda.
If this is the only attribute, it is tacked onto whatever the input was. So if your Input event was a json object with keys original_key1 and some_other_key your output with just the above result path would be:
{
"original_key_1": some value,
"some_other_key": some other value,
"my_path": the output of your lambda
}
Now if you add OutputPath, this cuts off everything OTHER than the path (AFTER adding the result path!) in the next output.
If you added OutputPath="$.my_path" you would end up with a json of:
{ output of your lambda }
(your output better be a json comparable object, like a python dict!)
InputPath does the same thing ... but for the Input. It cuts off everything other than the path described, and that is the only thing sent into the lambda. But it does not stop the input from being appeneded - so InputPath + ResultPath results in less being sent into the lambda, but everything all together on the exit
There isn't really a loop logic like the one you describe however - Task and State Machine definitions are static directions, not dynamic logic.
You can simply handle it inside the lambda. This is kinda the preferred method. HOWEVER if you do this, then you should use a combination of OutputPath and ResultPath to 'cut off' the input, having replaced the various fields of the incoming event with whatever you want before returning it at the end.

Related

Camunda, how to inject subprocess with specific parameters from main process

I have a Camunda flow with a Call Activity (sequential), the call Activity calls several subflows based on a list of process keys (ids) in a certain order.
For instance I get a list of ["flow-1", "flow-2"], then flow-1.bpmn and flow-2.bpmn are executed.
But, also in the scope is flow specific data, added to the scope in "Read LOT Configuration". For instance [{"name", "flow-1", "identifier" : "some-data"}, {name: "flow-2", "identifier" : "some other data"}].
I would like the call activity to determine that for flow-1, I need to send the flow-1 related object along.
I do not want to send the entire collection, but only the flow specific data.
How can I achieve this?
Some ideas:
a) use the element variable from the call activity settings as key to extract the correct data element in a data mapping
b) surround the call activity with a multi-instance embedded sub process. In this scope you will have the element variable (processId), which can then be used to perform delegate variable mapping (https://docs.camunda.org/manual/7.16/reference/bpmn20/subprocesses/call-activity/#delegation-of-variable-mapping)
c) pass the processID as data and fetch the configuration for the particular process inside its sub process implementation only

How to transit from Choice State Step Function?

The input that is being sent from previous state is in this form:
[
{
"bucketName": "test-heimdall-employee-data",
"executionId": "ca9f1e5e-4d3a-4237-8a10-8860bb9d58be_1586771571368",
"feedType": "lenel_badge",
"chunkFileKeys": "chunkFileLocation/lenel_badge/68ac7180-69a0-401a-b30c-8f809acf3a1c_1586771581154.csv",
"sanityPassFileKeys": "chunkFileLocation/lenel_badge/0098b86b-fe3c-45ca-a067-4d4a826ee2c1_1586771588882.json"
},
{
"bucketName": "test-heimdall-employee-data",
"executionId": "ca9f1e5e-4d3a-4237-8a10-8860bb9d58be_1586771571368",
"feedType": "lenel_badge",
"errorFilePath": "error/lenel_badge/2a899128-339d-4262-bb2f-a70cc60e5d4e/1586771589234_2e06e043-ad63-4217-9b53-66405ac9a0fc_1586771581493.csv",
"chunkFileKeys": "chunkFileLocation/lenel_badge/2e06e043-ad63-4217-9b53-66405ac9a0fc_1586771581493.csv",
"sanityPassFileKeys": "chunkFileLocation/lenel_badge/f6957aa7-6e22-496a-a6b8-4964da92cb73_1586771588793.json"
},
{
"bucketName": "test-heimdall-employee-data",
"executionId": "ca9f1e5e-4d3a-4237-8a10-8860bb9d58be_1586771571368",
"feedType": "lenel_badge",
"errorFilePath": "error/lenel_badge/8050eb12-c5e6-4ae9-8c4b-0ac539f5c189/1586771589293_1bb32e6c-03fc-4679-9c2f-5a4bca46c8aa_1586771581569.csv",
"chunkFileKeys": "chunkFileLocation/lenel_badge/1bb32e6c-03fc-4679-9c2f-5a4bca46c8aa_1586771581569.csv",
"sanityPassFileKeys": "chunkFileLocation/lenel_badge/48960b7c-04e0-4cce-a77a-44d8834289df_1586771588870.json"
}
]
state machine workflow design:
How do I extract "feedType"value from the above inputs and transit to next state and also pass entire inputs to next state?
Thanks
You can access the input JSON you started your statemachine with using: $$.Execution.Input.todo. Other than that you can't directly access previous state from one step to the next.
As an example lets say you have A->B->C
Lets say you went through A which gave a new field: a : 1, and then you went through B and it returns b : 2, when you get to C you will only have b : 2. But if B also return a : 1 you would then have {a : 1, b : 2} at C. Which is typically what you do to pass state from a step a couple of steps prior.
There are other things which people do, such as storing data in an s3 bucket and accessing that bucket in different stages. You can also query a step function as well but that can be messy.
Other hacks include adding a pass step in a parallel block, but these hacks are not good, the correct way is to pass the data on between your steps, or hopefully have what you need in your execution input.
Looking at your previous state input it looks like feed_type is a constant. Assuming key to your entire input is "input" so that it's dictionary like {"input":[{...},{...}]} and so on. So to access the value of feed_type you can simply do $.input[0].feed_type.
Choice state by default passes the entire input passed to it into the next stage. So to whatever next stage it goes to, that stage is going to have same input that was passed to choice state.
To understand it better or as a proof of concept check the below Step Function in which Hello state is a choice state and other 2 states are simple pass states.
And if you will see below the input and output of Choice state. It's the same.
Hope it helps.

Asynchronously populate/pre-fill multiple, user mutable `#State` values when using SwiftUI?

I have some TextField(s) with “.text” values that are supposed to be populated by a method called within “init()” (can be moved) that asynchronously calls a completion handler with a struct of data from the network.
The thing is... the user can also begin typing into them manually in the meantime and the completion callback shouldn’t overwrite the manually edited values.
I’m not sure how to:
Update the values of the #State String variables to replace the existing values only if they haven’t been modified by the user yet... while also having them be mutable by the end-user.
Update N number of the #State values from the same request at once. One request is used to pull all of the data in, so mapping into a single value while having it be mutable as noted above is a head scratcher at the moment.
It seems like a job for Combine, just not sure where to start yet.
I'm assuming the user-edit is per-field and all other fields should be left alone.
Move all state inside an ObservableObject, make the state variables #Published, take a publisher from each and create a sink from each setting a variable if stateX != initialStateXValue { stateXUserModified = true } inside each sink and have a method networkUpdate(loadedData:) on the ObservableObject which only sets the state if the associated stateXUserModified is false.

Dialogflow webhook set parameter value

My intent sends a webhook as part of slot filling if a parameter is missing from the user query. My webhook then uses logic to estimate the value of the parameter. How can I return this parameter as part of the WebhookResponse object? I am using the C# client library in an ASP.NET Core app.
My code is:
string fulfillmentText;
WebhookRequest request = null;
using (var reader = new StreamReader(Request.Body))
{
request = jsonParser.Parse<WebhookRequest>(reader);
}
//If Parameter-1 has no value
if (request.QueryResult.Fields["Parameter-1].StringValue.Length == 0)
{
fulfillmentText = "I have guessed the value of Parameter-1";
//I apply some logic that is unimportant to this question
//For the sake of simplicity, say I estimate the value of Parameter-1 to be "foobar"
//I want to be able to give the parameter this value like this:
parameter["Parameter-1"] = "foobar"
}
UPDATE
So, I have pretty much got it all working using Prisoner's method. I will retry sid8491's at some point too. My intent is trying to obtain a user's address. I have required custom entities to retrieve the street number, street name, suburb and state.
Without creating any contexts myself, the following context is automatically generated by Dialogflow: projects/telebot-pianomoves-v1/agent/sessions/2b42cbc8-2418-4231-e4c0-bd3a175f2ea8/contexts/1320fe35-4329-4176-b136-9221dfaddd4e_id_dialog_context. I receive this context in my webhook, and can then CHANGE the value of a parameter. Let's assume $Suburb_Entity had no value in the webhook request and my code then returned the above context with the a new value for Suburb_Entity. My code successfully changes the Suburb_Entity from "" to aspendale as can be seen by the webhook response json:
Now the odd thing is, although I changed the Suburb_Entity to an actual value in the outputContext of my webhook response, the actual parameter $Suburb_Entity only changes to the new value of Suburb_Entity from the outputContext on the NEXT detect intent request. So, keeping in mind the fact that I returned the new Suburb_Entity in the outputContext of the webhook response, this is the detect intent response I get - noting that $Suburb_Entity is yet to be changed:
On the next detect intent request, the webhook request parameter Suburb_Entity is set to aspendale and $Suburb_Entity also equals aspendale. The important thing about this, is $Suburb_Entity only changed to the outputContext parameter value on the NEXT detect intent request, of which would have triggered another webhook. $Suburb_Entity did not change during the same detect intent request as when I modified the outputContext parameter Suburb_Entity, but in the next. This leads me to believe that somehow, $Suburb_Entity inherits parameter values from this automatically generated context. The issue here, is that when my webhook responds with the outputContext paramter Suburb_Entity equalling aspendale, $Suburb_Entity does not change to this value until the next request. This means that if all the other parameters have values set, but $Suburb_Entity is yet to have changed value, then allRequiredParamsSet == false. If I return the Suburb_Entity in the outputContext, I want it to immediately change the value of $Suburb_Entity without requiring another detect intent request so that allRequiredParamsSet == true in such a circumstance. I tried setting the default value by doing this (it didn't work):
An alternative of course would be a way for me to force allRequiredParamsSet = true. I save the parameter values from this the context parameter, not the actual response. So I don't need $Suburb_Entity, I just want the intent to think that it has a value.
Cheers
When you use a webhook for "slot filling", the intention is that you return the prompts you want to ask the user for and continue to use the same Intent to handle the responses. You're not expected to create values yourself.
If you want to "fill in" some answers that are used in the static "response" section of the Dialogflow Intent, or if you just want to record the answers so you can use them later, you can set the parameters of a Context. In the response string, you can refer to this value as #context-name.parameter-name.
Update
I don't know the internal mechanics of slot filling, but it doesn't surprise me that setting a value in the internal context for the input parameters doesn't "register" until the next round of handling the Intent.
The webhook for slot filling isn't intended to create values - it is intended to handle values and create prompts for the user to respond to. Intents are generally about processing user inputs and webhooks about handling them.
My workaround suggested that if you want this for output, you use the context for output.
There are multiple steps for get it done:
First give an event in intent
Check your condition in webhook
If your condition is satisfied, invoke the intent by calling the event from webhook which you have defined in step 1
Pass the paylaod (in json format) along with event calling, give parameters in the payload
In the intent, give default value of parameter as #eventName.parameterName
Hope it helps.

how to get list of arguments to handler in delayed_job rails

I have a list of all the scheduled jobs which I can get using the command
Delayed::Job.all
Every job has a handler field(string) which contains a '-' separated arguments. I want to find one of the arguments of this string. One way is obviously to split the string and extract the value but this method will fail if there is ever any change in the list of arguments passed.
Below given is the handler string of one of my job objects:
"--- !ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper\njob_data:\n job_class: ActionMailer::DeliveryJob\n job_id: 7ce42882-de24-439a-a52a-5681453f4213\n queue_name: mailers\n arguments:\n - EventNotifications\n - reminder_webinar_event_registration\n - deliver_now\n - mail#gmail.com\n - yesha\n - 89\n locale: :en\n"
I want to know if there is any way, I can send extra arguments to job object while saving it which can be used later instead of searching in the handler string.
Or, if not this, can i get a list of arguments of handler rather than parsing the string and using it.
Kindly help!
There is a method instance_object for Delayed::Job instances which returns the deserialized handler
job = Delayed::Job.first
handler = job.payload_object
You can use your handler as needed, such as handler.method
To access the job data:
data = job.payload_object.job_data
To then return the actual job class that was queued, you deserialize the job data:
obj = ActiveJob::Base.deserialize(data)
If your job is a mailer and you want to access the parameters to your mailer, then this is where things get a bit hacky and I'm unsure if there's a better way. The following will return all of the data for the mailer as an array containing the mailer class, method names, and arguments.
mailer_args = obj.instance_variable_get :#serialized_arguments
Finally, you can deserialize all of the mailer arguments with the following which will contain the same data as mailer_args, but with any ActiveRecord objects deserialized (with the form gid://...) to the actual instances passed to the mailer.
ActiveJob::Arguments.deserialize(mailer_args)