nuecho / rivr

Rivr is a lightweight open-source dialogue engine enabling Java developers to easily create enterprise-grade VoiceXML applications.
http://rivr.nuecho.com
Other
61 stars 23 forks source link

what is default time out set for rivr application #25

Open D41138673 opened 2 years ago

D41138673 commented 2 years ago

One of IVR application is transfering call using subdialog option to our application developed using Rivr framework. But they are getting "Dialog exiting" response from our application , even though rivr application logs shows control still processing the request. So before rivr application retrun the result back the cller application is terminating call saying they got the "Exit" response.

Is there any default timeout defined in thie rivr framework servlet "VoiceXmlDialogueServlet"

gawi commented 2 years ago

The default timeout is 5 minutes. The dialogue is waiting up to 5 minutes to receive an input turn from the VoiceXML platform.

See https://nuecho.github.io/rivr/javadoc/com/nuecho/rivr/core/servlet/DialogueServlet.html

You can override the default globally by providing the com.nuecho.rivr.core.controllerTimeout servlet init-arg with a different value.

In your case though, I would recommend overriding the timeout by providing a value in the DialogueUtils.doTurn method. See https://nuecho.github.io/rivr/javadoc/com/nuecho/rivr/core/dialogue/DialogueUtils.html#doTurn(O,%20com.nuecho.rivr.core.dialogue.DialogueContext,%20com.nuecho.rivr.core.util.Duration)

nmvprasad commented 2 years ago

Currently we are facing problem other application through subdialog calling our application (developed using rivr framework) exising after 10 seconds but still rivr application flow is executing not returning control. So we are not sure why other application is getting the control back with "Exit" block without we send return. When we check the log rivr application is still executing the flow. I really approciate all your help on answering our questions

nmvprasad commented 2 years ago

And tyo set the timeout we are not starting the subdialog other application is starting the subdialog and calling our application . When we check with them regarding timeout they set the timeout period as 5 mins. but currently dialog is terminating after 10 seconds

nmvprasad commented 2 years ago

Is there any restriction calling restful web services (using RestTemplate) within rivr servlet in one of the step/turn?

gawi commented 2 years ago

10 seconds is the other timeout, i.e. the maximum time allowed for the dialogue to generate the next output turn. If the dialogue thread is making a backend query (like a REST call) and it takes more than 10 seconds, the servlet thread will time out. You can change the global timeout. See com.nuecho.rivr.core.dialogueTimeout servlet init-arg in https://nuecho.github.io/rivr/javadoc/com/nuecho/rivr/core/servlet/DialogueServlet.html

When the servlet thread times out, the VoiceXML application will terminate with <exit>, because this is the default ErrorHandler. If you are implementing a VoiceXML subdialog, you might want to change the ErrorHandler to use your own custom implementation and use a <return> instead of <exit>, to ensure a failure in your dialogue will not terminate the calling dialogue (your calling IVR application in this case). Something like this:

package com.nuecho.rivr.cookbook.dialogue;

import com.nuecho.rivr.core.servlet.*;
import com.nuecho.rivr.voicexml.servlet.*;
import com.nuecho.rivr.voicexml.turn.last.*;

public class DialogueServlet extends VoiceXmlDialogueServlet {

    @Override
    protected void initializeVoiceXmlDialogueServlet() {

        ErrorHandler<VoiceXmlLastTurn> customErrorHandler = new ErrorHandler<VoiceXmlLastTurn>() {

            @Override
            public Return handleError(Throwable error) {
                String message = error.getMessage();
                if (message == null) {
                    message = "no message";
                }
                return new Return("errorReturn", "error.subdialog.invoke", "dialogue error: " + message);
            }
        };

        setErrorHandler(customErrorHandler);
    }

}
nmvprasad commented 2 years ago

Thank you details and this help us fix the issue . One more question if any of Rest API calls taking more time. To keep the customer engage planning to play some audio prompt until we get the response from API call. Is there anyway I can do this in asynchronously and use callback technique to stop playing audio prompt once API call completed. Now if we playing audio prompt 15 seconds it is playing entire 16 seconds even though API call completed with in 8 or 10 seconds

gawi commented 2 years ago

What you need is a fetch audio. A fetch audio is an audio file that will be played during the fetching of the next document until the document is completely fetched.

Here's two way to set a fetch audio.

1- Add the fetch audio to the submit element:

package com.nuecho.rivr.cookbook.dialogue;

import com.nuecho.rivr.core.dialogue.*;
import com.nuecho.rivr.voicexml.dialogue.*;
import com.nuecho.rivr.voicexml.turn.first.*;
import com.nuecho.rivr.voicexml.turn.input.*;
import com.nuecho.rivr.voicexml.turn.last.*;
import com.nuecho.rivr.voicexml.turn.output.*;
import com.nuecho.rivr.voicexml.turn.output.audio.*;
import com.nuecho.rivr.voicexml.turn.output.fetch.*;

public class Dialogue implements VoiceXmlDialogue {

    @Override
    public VoiceXmlLastTurn run(VoiceXmlFirstTurn firstTurn, VoiceXmlDialogueContext context)
            throws Exception {

        DocumentFetchConfiguration documentFetchConfiguration = new DocumentFetchConfiguration();
        documentFetchConfiguration.setFetchAudio("/audio/fetch.wav");               
        context.getFetchConfiguration().setDocumentFetchConfiguration(documentFetchConfiguration);

        Message waitMessage = OutputTurns.message("wait-message").addAudioItem(new SpeechSynthesis("Please wait while we obtain your information.")).build();             
        VoiceXmlInputTurn inputTurn = DialogueUtils.doTurn(waitMessage, context);

        Thread.sleep(4000); // simlulate wait         
        Message resultMessage = OutputTurns.message("result")
                                           .addAudioItem(new SpeechSynthesis("Your confirmation number is 8 9 1 3 2."))
                                           .build();        
        inputTurn = DialogueUtils.doTurn(resultMessage, context);

        //end of dialogue
        return new Exit("exit");
    }
}

This will add fetchaudio to the submit element:

<submit fetchaudio="/audio/fetch.wav" method="post" namelist="inputTurn" next="/rivr-cookbook/dialogue/6e695c26-0860-4184-b6d1-152bce1f2c8f/0/wait-message"/>

2- Add fetch audio propoerties to the VoiceXML document:

package com.nuecho.rivr.cookbook.dialogue;

import com.nuecho.rivr.core.dialogue.*;
import com.nuecho.rivr.voicexml.dialogue.*;
import com.nuecho.rivr.voicexml.rendering.voicexml.*;
import com.nuecho.rivr.voicexml.turn.first.*;
import com.nuecho.rivr.voicexml.turn.input.*;
import com.nuecho.rivr.voicexml.turn.last.*;
import com.nuecho.rivr.voicexml.turn.output.*;
import com.nuecho.rivr.voicexml.turn.output.audio.*;
import com.nuecho.rivr.voicexml.turn.output.fetch.*;

public class Dialogue implements VoiceXmlDialogue {

    @Override
    public VoiceXmlLastTurn run(VoiceXmlFirstTurn firstTurn, VoiceXmlDialogueContext context)
            throws Exception {

        DefaultFetchConfiguration fetchConfiguration = context.getFetchConfiguration();
        fetchConfiguration.setDefaultFetchAudio("/audio/fetch.wav");

        //customize further the fetchaudio behavior:       
        context.getProperties().put(VoiceXmlDomUtil.FETCH_AUDIO_DELAY_PROPERTY, "1s"); //triggers after 1s 
        context.getProperties().put(VoiceXmlDomUtil.FETCH_AUDIO_MINIMUM_PROPERTY, "2s"); //plays at least 2s of fetch audio               

        Message waitMessage = OutputTurns.message("wait-message")
                                         .addAudioItem(new SpeechSynthesis("Please wait while we obtain your information."))
                                         .build();

        VoiceXmlInputTurn inputTurn = DialogueUtils.doTurn(waitMessage, context);

        Thread.sleep(4000); // simlulate wait         
        Message resultMessage = OutputTurns.message("result")
                                           .addAudioItem(new SpeechSynthesis("Your confirmation number is 8 9 1 3 2."))
                                           .build();

        inputTurn = DialogueUtils.doTurn(resultMessage, context);

        //end of dialogue
        return new Exit("exit");
    }
}

This will add the following properties to the document:

<?xml version="1.0" encoding="UTF-8"?>
<vxml application="/rivr-cookbook/dialogue/root/1939eccb-376a-4de1-b240-11d4152922e8" version="2.1" xmlns="http://www.w3.org/2001/vxml">
    <script>application.rivr.localErrorHandling = false; application.rivr.inputTurn = {};</script>
    <property name="fetchaudio" value="/audio/fetch.wav"/>
    <property name="fetchaudiominimum" value="2s"/>
    <property name="fetchaudiodelay" value="1s"/>
    <form id="form">
        <!-- ... -->
    </form>
</vxml>

For both methods, the fetch audio will remain for the rest of the dialogue because it is set in the VoiceXmlDialogueContext. So if it is no longer necessary following that point in the dialogue, the context should be reset to its previous state.

nmvprasad commented 2 years ago

Thank you we will try these options and let you know result

D41138761 commented 2 years ago

10 seconds is the other timeout, i.e. the maximum time allowed for the dialogue to generate the next output turn. If the dialogue thread is making a backend query (like a REST call) and it takes more than 10 seconds, the servlet thread will time out. You can change the global timeout. See com.nuecho.rivr.core.dialogueTimeout servlet init-arg in https://nuecho.github.io/rivr/javadoc/com/nuecho/rivr/core/servlet/DialogueServlet.html

When the servlet thread times out, the VoiceXML application will terminate with , because this is the default ErrorHandler. If you are implementing a VoiceXML subdialog, you might want to change the ErrorHandler to use your own custom implementation and use a instead of , to ensure a failure in your dialogue will not terminate the calling dialogue (your calling IVR application in this case). Something like this:

package com.nuecho.rivr.cookbook.dialogue;

import com.nuecho.rivr.core.servlet.*;
import com.nuecho.rivr.voicexml.servlet.*;
import com.nuecho.rivr.voicexml.turn.last.*;

public class DialogueServlet extends VoiceXmlDialogueServlet {

    @Override
    protected void initializeVoiceXmlDialogueServlet() {

        ErrorHandler<VoiceXmlLastTurn> customErrorHandler = new ErrorHandler<VoiceXmlLastTurn>() {

            @Override
            public Return handleError(Throwable error) {
                String message = error.getMessage();
                if (message == null) {
                    message = "no message";
                }
                return new Return("errorReturn", "error.subdialog.invoke", "dialogue error: " + message);
            }
        };

        setErrorHandler(customErrorHandler);
    }

}

Is there any way we can get VoiceXmlDialogueContext in the handleError method?

gawi commented 2 years ago

No. It's not possible to obtain it from the handleError method. Maybe in Rivr 2.0...