Closed ConcreteLlama closed 5 years ago
Hi @ConcreteLlama, the AsyncHandler<PostContentRequest, PostContentResult>
will monitor the request status of
postContentAsync(PostContentRequest, AsyncHandler<PostContentRequest,PostContentResult>)
method.
In your example, to add an intent to a lex bot you're probably using the
putIntentAsync(PutIntentRequest, AsyncHandler<PutIntentRequest,PutIntentResult>)
method from the AmazonLexModelBuildingAsyncClient, which will require a different AsyncHandler.
@debora-ito I probably should have been clearer - I'm not using the API to alter the Lex bot in any way and never use putIntentAsync. The only request I ever make in the SDK is using postContentAsync. I mentioned adding an intent (which I did via the web UI) as it is an easy way to get the bot into a state where it logs an error but does not trigger onError.
So basically the situation is:
I would have thought that onError should be triggered regardless of the reason for the failure of the postContentAsync request so that we can programatically determine that something has gone wrong and handle the situation accordingly.
Class looks like this:
LexImplementor implements AsyncHandler<PostContentRequest, PostContentResult>
I build my AmazonLexRuntimeAsync using an AmazonLexRuntimeAsyncClientBuilder. Once built, the only 2 methods I ever call on it are:
currentAWSRequest = lexClient.postContentAsync(postContentRequest, this);
and
lexClient.shutdown();
one I'm done with it.
The class implements:
@Override
public void onError(Exception e) {
// Code goes here
}
and
@Override
public void onSuccess(PostContentRequest initialRequest, PostContentResult response) {
// Code goes here
}
(obviously in my case the method bodies are filled with code including some log lines).
onError is never triggered - at least not in the scenario I mentioned, but it's possible there are other scenarios that don't trigger it.
Just to add to this, I'm also not seeing an onError triggered when there's a DependencyFailedException (exactly the same setup as before, just trying to use a bot with postContentAsync):
Received error response: com.amazonaws.services.lexruntime.model.DependencyFailedException: Invalid Lambda Response: Received error response from Lambda: Handled (Service: AmazonLexRuntime; Status Code: 424; Error Code: DependencyFailedException; Request ID: 420886d4-40c9-11e9-b4eb-aff6b51d4813)
Connection manager is shutting down
http-outgoing-0: Close connection
shutting down output of runtime.lex.eu-west-1.amazonaws.com/34.246.96.48:443
closing runtime.lex.eu-west-1.amazonaws.com/34.246.96.48:443
Reaper thread:
java.lang.InterruptedException: sleep interrupted
java.lang.Thread.sleep(Native Method)
com.amazonaws.http.IdleConnectionReaper.run(IdleConnectionReaper.java:188)
Shutting down reaper thread.
Connection manager shut down
I've since worked out what was wrong with the Lambda function but the issue here is that onError was not triggered.
Thank you for the clarifications! But I couldn't reproduce the issue.
I put my bot in a NOT_BUILT status as you described. Here's my AsyncHandler:
public class AsyncPostContentHandler implements AsyncHandler<PostContentRequest, PostContentResult>
{
public void onSuccess(PostContentRequest req, PostContentResult res) {
System.out.println("Request returned:");
System.out.println(res.getMessage());
System.exit(0);
}
public void onError(Exception e) {
System.out.println("Request ERROR here!!!");
System.out.println(e.getMessage());
System.exit(1);
}
}
And here's my client:
AmazonLexRuntimeAsync lex = AmazonLexRuntimeAsyncClientBuilder.defaultClient();
PostContentRequest postContentRequest = new PostContentRequest()
.withBotName(BOT_NAME)
.withBotAlias(ALIAS)
.withUserId(USER_ID)
.withContentType("text/plain; charset=utf-8")
.withInputStream(INPUT_STREAM);
Future<PostContentResult> future_res = lex.postContentAsync(postContentRequest, new AsyncPostContentHandler());
Here's my log when I run the client:
Request ERROR here!!! Invalid Bot Status: Bot OrderFlowersTest has status NOT_BUILT (Service: AmazonLexRuntime; Status Code: 400; Error Code: BadRequestException; Request ID: xxxxxx)
Showing Request ERROR here!!!
means it's going through the onError()
method.
I noticed you are calling the AsyncHandler using this
, I wonder if it is invoking the right handler.
For further analysis, could you provide a reproducible code with your client call?
@debora-ito Thank you for checking this out. I found that there were 2 issues that were affecting my code, one of which was definitely an error with my code and the other I'm not sure.
1) A method I was using in onError was unexpectedly blocking, which I have now fixed and was obviously an issue with my code. 2) It seems that I don't get an error response on my request until the InputStream has finished
For 2), I can see the API making the initial post content request then sending the raw data (which means that this isn't caused by the read method blocking). However, it will keep reading from that InputStream and sending more chunks of data until the InputStream returns -1. When it finally stops streaming the data (for example, if my code has detected that there has been a long enough period of consecutive silence), then I finally get a response from Lex saying that the bot is in a NOT_BUILT state.
Is this a bug or is it just that I've missed something? I would have expected that if I send a request to a bot that is not currently usable (such as being in the NOT_BUILT state), the POST request would get a an error response immediately.
I have made some Java code to demonstrate this behaviour. It has an InputStream that returns data for 10 seconds then stops. As you can see, the Lex API keeps sending data until the InputStream has ended, at which point it finally gets a response. This is obviously the expected behaviour in good scenarios where there are no issues with the bot, but I would expect to get an onError immediately if the bot is in a bad state.
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.handlers.AsyncHandler;
import com.amazonaws.services.lexruntime.AmazonLexRuntimeAsync;
import com.amazonaws.services.lexruntime.AmazonLexRuntimeAsyncClient;
import com.amazonaws.services.lexruntime.AmazonLexRuntimeAsyncClientBuilder;
import com.amazonaws.services.lexruntime.model.PostContentRequest;
import com.amazonaws.services.lexruntime.model.PostContentResult;
public class LexTester implements AsyncHandler<PostContentRequest, PostContentResult> {
public class XMillisecondInputStream extends InputStream {
static final byte ZERO = (byte)0;
final byte[] oneByte = new byte[1];
final long endTime;
public XMillisecondInputStream(long timeoutMS) {
endTime = System.currentTimeMillis() + timeoutMS;
}
@Override
public int read(byte[] b, int off, int len) {
if (System.currentTimeMillis() > endTime) {
System.out.println("Input stream done, returning -1");
return -1;
}
Arrays.fill(b, off, off+len, ZERO);
System.out.println("Put " + len + " bytes");
return len;
}
@Override
public int read() throws IOException {
int bytesRead = read(oneByte, 0, 1);
if (bytesRead == -1) {
return -1;
}
return ((int) oneByte[0]) & 0xFF;
}
}
private final String botName, botAlias, userId, region, accessKey, secretKey;
private AmazonLexRuntimeAsync lexClient;
public LexTester(String botName, String botAlias, String userId, String region, String accessKey, String secretKey) {
this.botName = botName;
this.botAlias = botAlias;
this.userId = userId;
this.region = region;
this.accessKey = accessKey;
this.secretKey = secretKey;
buildClient();
}
private void buildClient() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
AmazonLexRuntimeAsyncClientBuilder clientBuilder = AmazonLexRuntimeAsyncClient.asyncBuilder();
clientBuilder.setRegion(region);
clientBuilder.setCredentials(new AWSStaticCredentialsProvider(awsCreds));
lexClient = clientBuilder.build();
}
public void postContent() {
PostContentRequest postContentRequest = new PostContentRequest();
postContentRequest.setBotName(botName);
postContentRequest.setBotAlias(botAlias);
postContentRequest.setUserId(userId);
postContentRequest.setAccept("audio/pcm");
postContentRequest.setContentType(
"audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false");
postContentRequest.setInputStream(new XMillisecondInputStream(10000));
lexClient.postContentAsync(postContentRequest, this);
}
@Override
public void onError(Exception arg0) {
System.out.println("I got an error!");
arg0.printStackTrace();
}
@Override
public void onSuccess(PostContentRequest arg0, PostContentResult arg1) {
System.out.println("Success");
}
public static void main(String[] args) {
LexTester lexTester = new LexTester("BOT_NAME", "ALIAS", "USER_ID", "REGION", "ACCESS_KEY", "SECRET_KEY");
lexTester.postContent();
}
}
If you turn the wire logs on you'll see that the response is obtained only after the whole request body with the inputstream is sent, so this is the expected behavior of the PostContent API.
Closing the issue, feel free to reopen if you have further questions.
(Note: Updated slightly to make it clearer that this issue occurs when doing a postContentAsync and is unrelated to anything like putIntentAsync)
Using SDK version: aws-java-sdk-1.11.511.jar My class implements AsyncHandler<PostContentRequest, PostContentResult>
I have an AmazonLexRuntimeAsync setup and this works just fine for the most part - I get onSuccess when a request successfully completes. However, I am not receiving onError - at least, I haven't come across a case where it is triggered yet (when it really should be).
As an example that is easy to reproduce, if I add an intent to a lex bot (in the Lex bot web UI) but do not build it, the bot will be in a "not ready for testing" state. If I then do a postContentAsync to this bot, Java SDK logs out the following:
Received error response: com.amazonaws.services.lexruntime.model.BadRequestException: Invalid Bot Status: Bot BookTrip has status NOT_BUILT (Service: AmazonLexRuntime; Status Code: 400; Error Code: BadRequestException; Request ID: 1d69c416-3f43-11e9-a89c-73d3afc738e1)
However, neither onSuccess or onError are triggered when this occurs.