Why is it not possible to access objects that seem to be in scope when pausing execution? - amazon-web-services

I'm learning Dart and Flutter, and I'm finding it a mostly pleasureable experience. I'm making an app that I want to communicate with Amazon AWS resources. However, I'm stuck with an issue that I haven't been able to resolve for a while now.
I'm making a function for getting keys and tokens necessary for making authenticated requests to the API at AWS. I'm using a library function from AWS Amplify to get an AuthSession object. If I set a breakpoint to just after the AuthSession object has been retrieved, it seems as if this object contains some object called AuthSession.credentials. This in turn contains awsAccessKey, awsSecretKey and sessionToken, which are the tokens and keys that I need. I can access them in the debug console when execution is paused.
Future<AWSCredentials> getAWSCredentials() async {
final AuthSession authSession = await Amplify.Auth.fetchAuthSession(
options: CognitoSessionOptions(getAWSCredentials: true));
final a = 1; // I set a breakpoint on this line
//final AWSCredentials awsCredentials = authSession.credentials;
//return awsCredentials;
}
VS Code screenshot of objects in scope at breakpoint
However, if I try to make the function return this AuthSession (by uncommenting the last two lines of the above function), or one of the tokens directly, it doesn't compile anymore and I get the error message
The getter 'credentials' isn't defined for the type 'AuthSession'.
Try importing the library that defines 'credentials', correcting the name to the name of an existing getter, or defining a getter or field named 'credentials'. dart(undefined_getter)
I tried to dig into the code defining the class AuthSession, and it doesn't seem to contain any reference to the credentials object. However, it's obviously there at runtime. Why can't I access it?

The class AuthSession does not contain any member called credentials, so when casting the result of fetchAuthSession() to an AuthSession, it is not possible to access that member. However, the subclass CognitoAuthSession does contain the credentials member, so casting the result to that type allows access to authSession.credentials.
So the call to fetchAuthSession() should be
final CognitoAuthSession authSession = await Amplify.Auth.fetchAuthSession(
options: CognitoSessionOptions(getAWSCredentials: true));

Related

Akka get response as ComletedStage from actor

I am referring to api
Patters.ask(actor, msg, duration);
here is sample
class MyActor extends AbstractBehavior{
interface Command{}
interface SomeMessage implements Command{ INSTANCE}
public Reveive<Comamnd> receive(){
return newReceiveBuilder().onMessage(SomeMessage.class, this::someMessage).build();
}
private Behavior<Command> someMessage(SomeMessage ref){
System.out.println("Dru lalal");
}
}
ActorRef<MyActor.Command> myActor = ...;
Future<Object> future = Patterns.ask(myActor, SomeMessage.INSTANCE, Duration.ofMillis(10000));
What is gone be object ?
Obviously this won't compile. Some part of picture is missing, but javadoc doesn't state what.
Call "Patterns.ask" suppose to return future with object, those value is provided by actor as business logic. But there is not business logic in actor. I assume there is suppose to be some kind of convention or mapping for method that returns value with what "Patters.ask" triggers.
Same is true about back logic. I will not able to define receiver since it expect to return Receiver not SomeObject and thus, api want't let me bind result to some message. Only thing I can do is manually pass ComputableFuture
ComputableFuture<MyOBject> future = new ComputableFuture<>();
myActor.tell(new Message(future));
private Behavior<Command> someMessage(Message message){
var result = compute();
message.future.comlete(result);
}
And here we go, I have manually manage everything, also issues with passing non serializable message, lifecycle of objects and so on.
Wrong objects is used. Instead of "AskPattern.ask" for new java typed dsl, I used classic "Patterns.ask".
Most of times new api objects has same object name but located in different package. I used to check only package name becouse while playing with in IDE they always next to each other since name is the same. I got used to ignore the classic "com.akka" objects while playing with api.
And here I got into trap, object name is different and not placed in IDE next to "classic" package object.

Is there a way to programmatically invoke a WebJob function from another function within the WebJob and still have the output binding work?

Here's the code:
[return: Table("AnalysisDataTable", Connection = "TableStorageConnection")]
public static async Task<OrchestrationManagerAnalysisData> InputQueueTriggerHandler(
[QueueTrigger("DtOrchestrnRequestQueueName",
Connection = "StorageQueueConnection")] string queueMsg,
[OrchestrationClient] DurableOrchestrationClient client, ILogger logger)
{
logger.LogInformation($"***DtOrchestrationRequestQueueTriggerHandler(): queueMsg = {queueMsg}");
await ProcessInputMessage(queueMsg, client, logger);
// Below is where the code goes to format the TableStorage Entity called analysisData.
// This return causes the above output binding to be executed, saving analysis data to
// Table Storage.
return analysisData;
}
The above code works fine and saves analysisData to TableStorage.
However when I put the output binding attribute on ProcessInputMessage() which is programatically invoked
rather that invoked as a result of a trigger everything works OK except there is no data output
to Table Storage.
[return: Table("AnalysisDataTable", Connection = "TableStorageConnectionName")]
public static async Task<OrchestrationManagerAnalysisData>
ProcessInputMessage(string queueMsg, DurableOrchestrationClient client, ILogger logger)
{
// Do the processing of the input message.
// Below is where the code goes to format the TableStorage Entity called analysisData.
// This return causes the above output binding to be executed, saving analysis data to
// Table Storage.
return analysisData;
}
QUESTION is there a way to cause an output binding to "trigger" when invoked programatically from another function within the WebJob?
I like the labor saving characteristics of output bindings and want to leverage them as much as possible, while also having well factored code, i.e. tight cohesion in each method.
Thanks,
George
is there a way to cause an output binding to "trigger" when invoked programatically from another function within the WebJob?
In short, No.
You send data by using the return value of the function which apply the output binding attribute in function. So, if you want to invoke another function and write data into Table Storage.
If you want to achieve the idea you want, you need to overwrite the return method. However, it is a package integration method, so I suggest that you could use the TableOperation object that inserts the customer entity to the Table Storage.
TableOperation insertOperation = TableOperation.Insert(customer1);
// Execute the insert operation.
table.Execute(insertOperation);
For more details, you could refer to this article.

AWS Lambda NodeJS locale/variable isolation

There is a concern about potential problem with reusable variables in aws-lambda.
A user's locale is passed as
Browser cookies => AWS API Gateway => Lambda (NodeJS 6.10)
On the server side localization is implemented with a static variable in a class. Presenting typescript code for clarity but can be done in pure ECMAScript.
Module Language.ts
export default class Language
{
public static Current: LanguageCode = LanguageCode.es;
}
Static Language.Current variable is used across different parts of the application for manual localization and it works perfectly on the client side (react + redux).
Lambda function
import {APIGatewayEvent, Context, Callback} from 'aws-lambda';
import Language from './pathToModule/Language.ts';
export const api = function(event: APIGatewayEvent, context: Context, callback: Callback)
{
Language.Current = event.headers.cookie.locale;
// do the logic here
}
Potential problem
According to AWS documentation NodeJS instances can be reused for different requests. It means that famous concurrent problems have to be considered, e.g.
User 1 calls lambda function. The locale is set to English.
In parallel user 2 calls the same lambda instance. The local is changed to Spanish.
User 1 code continues and reads modified (wrong) locale variable from the shared module Language.
How do you resolve this problem?
For convenience it is good to have only one place for locale change. As I understand the same concern exists for all famous i18n npm packages (i18next, i18n, yahoo i18n, etc).
One of the best practices for Lambda functions is to try and not write code which maintains state.
Here you are initializing the locale based on an initial request and applying it to all future requests, which is inherently flawed even on server based code, forget server less.
To fix this, you will need to initialize the localization library for each request, or at least maintain an in memory lazy map, which you can make use of use the current request's locale to achieve the desired localization.
There are several solutions:
Node JS container is reused only after a function process is finished (callback or error is occurred) (thanks to #idbehold). Thus there is always a unique context per a function call.
Refactor code and pass a locale variable back and force (#Yeshodhan Kulkarni suggestion).
For example, return a function as an intermediate result and use it before calling the result back.
var localizableResult = ...;
var result = localizableResult.Localize(requestedLocale).
If there is a need to use a local stack (kind of a thread context) for other projects there is a npm package node-continuation-local-storage.
Case 1 makes it really simple to use global variables for current locale.

AWS SWF - IllegalStateException: No context found. (method called outside the workflow definition)

I am writing an AWS SWF application using the flow framework. Getting an IllegalStateException: No context Found. It means that the method is called outside of the workflow definition code. while calling the following code:
private DecisionContextProvider contextProvider
= new DecisionContextProviderImpl();
private WorkflowClock clock
= contextProvider.getDecisionContext().getWorkflowClock();
Why am I getting this error and how to get rid of it?
This exception is thrown by getDecisionContext() when you call it outside of a workflow (it should only be called somewhere in the call hierarchy of your workflow implementation - ie, your WorkflowImpl ).
To avoid getting that error, you should only call getDecisionContext() while inside of a workflow or its constructor. The object only gets set in those circumstances (by the simple workflow framework), and doesn't exist outside of workflow execution, hence the IllegalStateException.

SFDC Apex Code: Access class level static variable from "Future" method

I need to do a callout to webservice from my ApexController class. To do this, I have an asycn method with attribute #future (callout=true). The webservice call needs to refeence an object that gets populated in save call from VF page.
Since, static (future) calls does not all objects to be passed in as method argument, I was planning to add the data in a static Map and access that in my static method to do a webservice call out. However, the static Map object is getting re-initalized and is null in the static method.
I will really appreciate if anyone can give me some pointeres on how to address this issue.
Thanks!
Here is the code snipped:
private static Map<String, WidgetModels.LeadInformation> leadsMap;
....
......
public PageReference save() {
if(leadsMap == null){
leadsMap = new Map<String, WidgetModels.LeadInformation>();
}
leadsMap.put(guid,widgetLead);
}
//make async call to Widegt Webservice
saveWidgetCallInformation(guid)
//async call to widge webserivce
#future (callout=true)
public static void saveWidgetCallInformation(String guid) {
WidgetModels.LeadInformation cachedLeadInfo =
(WidgetModels.LeadInformation)leadsMap.get(guid);
.....
//call websevice
}
#future is totally separate execution context. It won't have access to any history of how it was called (meaning all static variables are reset, you start with fresh governor limits etc. Like a new action initiated by the user).
The only thing it will "know" is the method parameters that were passed to it. And you can't pass whole objects, you need to pass primitives (Integer, String, DateTime etc) or collections of primitives (List, Set, Map).
If you can access all the info you need from the database - just pass a List<Id> for example and query it.
If you can't - you can cheat by serializing your objects and passing them as List<String>. Check the documentation around JSON class or these 2 handy posts:
https://developer.salesforce.com/blogs/developer-relations/2013/06/passing-objects-to-future-annotated-methods.html
https://gist.github.com/kevinohara80/1790817
Side note - can you rethink your flow? If the starting point is Visualforce you can skip the #future step. Do the callout first and then the DML (if needed). That way the usual "you have uncommitted work pending" error won't be triggered. This thing is there not only to annoy developers ;) It's there to make you rethink your design. You're asking the application to have open transaction & lock on the table(s) for up to 2 minutes. And you're giving yourself extra work - will you rollback your changes correctly when the insert went OK but callout failed?
By reversing the order of operations (callout first, then the DML) you're making it simpler - there was no save attempt to DB so there's nothing to roll back if the save fails.