AWS Lambda - Asynchronously invoked function but nothing happens - amazon-web-services

I have 2 lambda functions, my first function w/c we'll call "PostStep" invokes another lambda function "RetryStep" asynchronously whenever a timeout occurs. It's been working fine ever since. Now I have to do some code changes, and during testing, a weird issue occurred.
Upon timeout, it still calls the RetryStep function asynchronously, but then the function is not really being invoked. I tried invoking the PostStep function again, then I noticed that's the time when the RetryStep function is really invoked, but with the previous request's data.
Here's how I'm doing the invocation:
LivePostingService.class
#Override
public void postTransaction(Transaction transaction) {
... some posting logic ...
conditionalCallRetryLambdaFunction(transaction);
}
private void conditionalCallRetryLambdaFunction(Transaction transaction) {
try {
String payload = objectMapper.writeValueAsString(transaction);
lambdaInvokerService.invokeAsync(lambdaRetryFunctionName, payload);
} catch (JsonProcessingException e) {
if(LOGGER.isErrorEnabled()) {
LOGGER.error(e.getMessage(), e);
}
}
}
LambdaInvokerService.class
#Service
public class LambdaInvokerServiceImpl implements LambdaInvokerService {
LOGGER.info("Calling lambda function: " + functionName + ", with payload: " + payload);
InvokeRequest req = new InvokeRequest()
.withFunctionName(functionName)
.withInvocationType(InvocationType.Event)
.withPayload(payload);
AsyncHandler<InvokeRequest, InvokeResult> asyncHandler = new AsyncHandler<InvokeRequest, InvokeResult>() {
#Override
public void onError(Exception e) {
LOGGER.error(e.getMessage());
}
#Override
public void onSuccess(InvokeRequest request, InvokeResult invokeResult) {
LOGGER.info("Success! " + invokeResult);
}
};
lambdaAsyncClient.invokeAsync(req, asyncHandler);
}
Here's my handler:
#Override
public Void handleRequest(DynamodbEvent dynamodbEvent, Context context) {
livePostingService.postTransaction(transaction);
return null;
}
As you can see from the code, the log Calling lambda function.. appears at the end of PostStep function, but the log Success! appears at the beginning of the PostStep function if i invoke it again.
It's the same code with what's currently on our production. I even did a git checkout on our master branch then ran it on dev, but the same issue still occurs. Do you have any idea about this?
Thanks!

Related

How would one unit test api call method (rxjava+retrofit)?

I'm trying to unit test an api call made with retrofit and rxjava.
In order to do that i'm mocking the api call object but api calls subscriber won't trigger its onNext method.
ApiCallsTest.java:
//custom object replacing api call response object
Observable<FastRechargeClass[]> apiObservable = Observable.just(fastRechargeList);
InterfaceAPI api = mock(InterfaceAPI.class);
when(retrofitApi.getApiInterface(context)).thenReturn(api); when(api.getLatestTransactions("token")).thenReturn(apiObservable);
apiCalls.getLatestTransactions("token",context);
ApiCalls.java:
public void getLatestTransactions(String token, final Context context) {
String methodName = "getLatestTransactions";
InterfaceAPI api = retrofitApi.getApiInterface(context);
Observable<FastRechargeClass[]> call = api.getLatestTransactions(token);
call.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new Observer<FastRechargeClass[]>() {
#Override
public void onSubscribe(Disposable d) {
WriteLog.print("onSubscribe");
}
#Override
public void onNext(FastRechargeClass[] fastRechargeClasses) {
fastRechargeManager.runUpdateFastRechargeDb(fastRechargeClasses);
}
#Override
public void onError(Throwable e) {
logOnFailureRequests(methodName, e.getMessage());
}
#Override
public void onComplete() {
}
});
}
When running test
onSubscribe is being called and it stops
You need to trigger event emission manually. To do this you need to call method
.blockingFirst()
or
.blockingGet()
depends of observable type you are using.
So you have to add
call.blockingGet()
at the end of getLatestTransactions method or this method should return created observable and call blocking get inside a test method.

Spring Boot #Async not working

I expect that uploadImage method finishes once the file is uploaded to AWS, while scanFile method is still running asynchronously in the background;
#RestController
public class EmailController {
#PostMapping("/upload")
#ResponseStatus(HttpStatus.OK)
public void uploadImage(#RequestParam MultipartFile photos) {
awsAPIService.uploadImage(photos);
}
}
...
#Service
public class AwsAPIService {
public void uploadImage(MultipartFile file) {
try {
File fileToUpload = this.convertMultiPartToFile(file);
String fileName = this.generateFileName(file);
s3client.putObject(new PutObjectRequest(AWS_S3_QUARANTINE_BUCKET_NAME,fileName, fileToUpload));
fileToUpload.delete();
// start scan file
scanFile();
} ...
}
#Async
public void scanFile() {
log.info("Start scanning");
String queueUrl = sqs.getQueueUrl("bucket-antivirus").getQueueUrl();
List<Message> messages = sqs.receiveMessage(new ReceiveMessageRequest().withQueueUrl(queueUrl)
.withWaitTimeSeconds(20)).getMessages();
for (Message message : messages) {
// delete message
...
}
}
}
...
#EnableAsync
public class AppConfig {
#Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(2);
taskExecutor.setQueueCapacity(200);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
}
But this seems still running synchronously. What is the problem here?
By default #Async and other Spring method-level annotations like #Transactional work only on the external, bean-to-bean method call. An internal method call from uploadImage() to scanFile() in the same bean won't trigger the proxy implementing the Spring behaviour. As per Spring docs:
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. #PostConstruct.
You could configure AspectJ to enable annotations on internal method calls, but it's usually easier to refactor the code.

How to mock a retrofit service observable calling onError?

I am testing this code.
service.getProducts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Result<Catalog<SoajsProductPreview>>>() {
#Override
public void onError(Throwable e) {
view.showErrorView(e);
}
#Override
public void onNext(Result<Product> products) {
view.showProducts(products)
}
#Override
public void onCompleted() {}
});
Testing that view.showProducts() the mocked service returns results works fine.
I do
when(service.getProducts().thenReturn(someObservable);
Now I want to test that view.ShowErrorView() is called when the service throws an error but I can't find a way to do that:
Obviously the following doesn't compile
when(service.getProducts().thenReturn(someException);
And this throws an exception immediately but doesn't call the Subscriber's onError method
when(service.getProducts().thenReturn(someException);
How can I get Subscriber.onError() called?
when(service.getProducts().thenReturn(Observable.error(someException))
should work. See the documentation starting here.

XSocket.net. how to send a message to a client from an object which is not a controller

I have a class that starts a server:
public class SocketServer
{
private static IXSocketServerContainer server = null;
public SocketServer()
{
server = XSockets.Plugin.Framework.Composable
.GetExport<IXSocketServerContainer>();
}
public bool StartServers()
{
try
{
server.StartServers();
return true;
} catch
{
return false;
}
}
this class has a method:
public void SendEventMessageToAllClients(string message)
{
XSockets.Core.XSocket.Helpers.XSocketHelper
.SendToAll<MyController>(new MyController(), message, "events");
}
where MyController is my own controller, it is implemented and the server can find it and this method work.
Now I would like to expand the functionality with a new method that allows me to send an event to an specific client:
public void SendEventMessageToClient(string clientId, string message)
{
XSockets.Core.XSocket.Helpers.XSocketHelper
.SendTo<MyController>(new MyController(),
p => p.ClientId == clientId, message, "events");
}
Is this the right approach or am I doing something wrong?
Thanks!
I would not recomend that approach, I have not even tested if that actaully works.
You create a new controller every time just to be able to access the extension method.
I am guessing that since you have this on the class starting the server you only use this as a publisher?
If so the correct way would be to install the XSockets.Client package and use the client pool to publish messages: client pool documentation
Example with client pool
The nice thing about the client pool is that you do not need to create an instance every time. The pool will reuse your connection to the controller.
Using the clientpool (or a real client connection) will ensure that the message pass through the Pipeline and all interceptors if you have any. Using a controller instance directly will never reach the pipline, interceptors etc.
//Get a pool client
ClientPool poolClient =
XSockets.Client.ClientPool.GetInstance("ws://127.0.0.1:4502/MyController", "*");
Methods for sending a message to the controller.
public void SendEventMessageToClient(Guid clientId, string message)
{
poolClient.Send(new {clientId, message}, "SendEventMessageToClient");
}
public void SendEventMessageToAllClients(string message)
{
poolClient.Send(message, "SendEventMessageToAllClients");
}
The controller
public void SendEventMessageToClient(Guid clientId, string message)
{
this.SendTo(p => p.ClientId == clientId, message, "SendEventMessageToClient");
}
public void SendEventMessageToAllClients(string message)
{
this.SendToAll(message, "SendEventMessageToAllClients");
}
Example with instance of controller
If you decide to use the way you have done you should at least create on ONE instance of the controller to use the in the server class.
Important: Using a controller instance directly will never reach the pipline, interceptors etc.
//Be aware of the fact that this controller NEVER will have a connection.
//It can only send to others, it can never receive messages!
MyController c = new MyController();
//You should probably have a Guid here instead of string
//Also note that the client have to subscribe for "events" to get the message
public void SendEventMessageToClient(Guid clientId, string message)
{
this.SendTo(p => p.ClientId == clientId, message, "SendEventMessageToClient");
}
public void SendEventMessageToAllClients(string message)
{
this.SendToAll(message, "SendEventMessageToAllClients");
}
Since I do not know what you are trying to accomplish Im not sure this is the best way, but one of the merhods above should work.
EDIT: Also, in a real application you probably dont have access to the MyController class since it probably is in a separate assembly not being referenced at compile time. So then you approach will not even be possible and the way to go then is client or clientpool
/Uffe
Uffe, you're right an the ClientPool is the right option for me, I had problems running your code because some of the mappings proposed by you are not working, here is your proposed solution slightly modified to make it run:
//Get a pool client
ClientPool poolClient = XSockets.Client.ClientPool.GetInstance("ws://127.0.0.1:4502/MyController", "*");
Methods for sending a message to the controller. ITextArgs are needed in this case
public void SendEventMessageToClient(Guid clientId, string message)
{
ITextArgs textargs = new TextArgs(mess, "SendEventMessageToClient");
poolClient.Send(new {clientId = guid, message = "Hello to one client"}, "SendEventMessageToClient");
}
Here, I TextArgs is not needed, it can be used, but string works also properly. It seems that the conversion to ITextArgs works fine here.
public void SendEventMessageToAllClients(string message)
{
poolClient.Send("hello all", "SendEventMessageToAllClients");
}
The controller: Only ITextArgs messages are mapped. Using string will not work.
public void SendEventMessageToClient(Guid clientId, ITextArgs message)
{
c.SendTo(p => p.ClientId == clientId, message.data, "events");
}
public void SendEventMessageToAllClients(ITextArgs message)
{
c.SendToAll(message.data, "events");
}
Thanks you very much Uffe for your help!

Rhino Mock Stub Async Method

I have a ViewModel which, in the constructor, makes a call to an async void method to add to a collection
public MyViewModel(ICommandHandler commandHandler)
{
_commandHandler = commandHandler;
SetupCollection();
}
private async void SetupCollection()
{
var commands = GetCommands();
foreach (var command in commands)
{
var response = await _commandHandler.ExecuteGetReply(command);
if (response != null)
Response.Add(response);
}
}
How exactly would I stub the _commandHandler.ExecuteGetReply() command to return a value?
Also, is it OK to have such a function in the constructor to do something like this? Or should this perhaps go within an... override void OnActivate() call (I'm using Caliburn Micro) ?
ICommandHandler.ExecuteGetReply appears to return a Task<Response> so you can do something like:
ICommand commandArg;
Response response;
stubHandler.Stub(h => h.ExecuteGetReply(commandArg)).Return(Task.FromResult(response));
I wouldn't call an async void method from your constructor however, since you will have no way of being notified when it has completed.