Dialogflow : Provide Response after delay - dialogflow-es

I have a requirement to trigger an event from webhook which calls follow-up intent after 20 seconds delay.
I am trying to trigger custom event from setTimeOut within promise so that it calls desired intent.
function payment(agent){
const delay = t => new Promise(resolve => setTimeout(resolve, t));
return delay(5000).then(() => {console.log('Hello');
agent.setFollowupEvent('payment_completed');
});
}
console.log gets executed but event is not triggered.Please help.

Related

How can I reassign the result of a listener function that is executed repeatedly?

I have a function which consumes a Queue from RabbitMQ and I want to save the result of every time it's executed to run some other code (e.g. save something in database).
The problem here is that it's only saved once, the listener keeps working fine and getting that information as the code within the function keeps being executed as I add more events to the queue but without reassigning the result of the execution to that variable:
Here's my code:
Controller (which calls the consumer)
async run() {
const eventData = await this.eventManager.consume(QueuesToConsume.USER_CREATED)
await this.createUserUseCase.run(eventData);
}
RabbitMQ consumer
async consume(queue: string): Promise<DomainEvent> {
let eventData: DomainEvent;
return new Promise<DomainEvent>(async (resolve, reject) => {
await this.channel.consume(queue, async (msg: Message) => {
console.log(`Message: \n ${Buffer.from(msg.content)} \n received successfully!`)
await this.channel.ack(msg)
eventData = JSON.parse(Buffer.from(msg.content).toString('utf8'))
console.log('Message acknowledged successfully')
resolve(eventData);
}).catch(err => {
console.log(`Error consuming the message: \n ${err}`)
reject(err)
});
})
}
So this is not working properly as eventData in the controller doesn't get every response and the useCase can only be executed the first time.
How can I fix this for eventData to get every result the consumer es returning?
PS: Note that I didn't copied the whole piece of code because it is not necessary, I can happily copy it if you need it to give me a proper answer!
I have found some other stack overflow forums that discussed this and in summary this can not be done, whether it is done with promises or with traditional async await, a variable can't just be reassigned to a value every time the listener listens to something.
I have found a workaround that allows me to achieve what I wanted at the very beginning using the Observer/Subject design pattern in which the RabbitMQ consumer that will be the subject will also notify the observers with the new event.
This way also helps a lot if you want that event to trigger two actions or usecases rather than one, you just have to add the new action as an observer and you're good to go!

Reporting during long running async function using set interval in node.js (backend service)

I need to report the status of a long running operation in node.js. The basic use case is outlined in the code below. awaiting the longProcess method I know will act synchronously to the caller, but I must await the method in my code. Should I handle this within the longProcess method? Not sure how to address this issue.
function sleep (ms: number) {
new Promise(resolve => setTimeout(resolve, ms));
}
let processedCount = 0;
async function longProcess() {
// really long operation
while (true) {
processedCount++;
await sleep(1000); // simulate long process
if (processedCount === 10) // just to end the test somehow
break;
}
}
async function report() {
console.log(processedCount);
}
async function main() {
const id = setInterval(report, 500);
await longProcess();
clearInterval(id);
}
main().then(() => console.log("Done"));
The sleep method is just for demonstration purposes to simulate a long running operation. 'longProcess' performs complex and time intensive processing. It calls a callback passed in to report back a processed count the caller. The class that contains the calling method (and the callback), also has a report method that I would like to call at regular intervals. And I need to be able to create a unit test for this
Your sleep function is not returning the promise you are creating. You are calling await on the value returned from the function, which in this case is undefined so it doesn't actually wait at all.
function sleep (ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}

Creating a slow reply from Dialogflow

I want to create a Dialogflow webhook that responds to the user slowly, so it more feels like someone is on the other end and takes a few seconds to reply.
I'm using the built-in code editor, and can create an Intent handler (see code), but I just don't know how to get it to reply slower.
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function welcome (agent) {
agent.add(`I'm replying too quickly!`);
}
function fallback (agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
agent.handleRequest(intentMap);
});
Best way to handle this is to add delay in the UI code.
Keep the Dialogflow Intent as it is, and once the bot response is received on the frontend, show it with a delay.
Below is an example of how we are handling it at Kommunicate
Dialogflow response comes without any delay, then on Javascript code, we show a typing indicator animation, add some delay using Javascript before displaying it.
Needing to reply slower is rarely a desired thing, to be honest. But the easiest way to do so is to use setTimeout() and delay for a little bit. (Don't delay too long - more than 5 or 10 seconds and Dialogflow will timeout.)
The catch with using setTimeout(), however, is that the handler will need to return a Promise. So you'll need to wrap the call to setTimeout() and the agent.add() in a Promise handler. A function that does this might look something like:
function respondSlowly( agent, msg, ms ){
return new Promise( resolve => {
setTimeout( () => {
agent.add( msg );
resolve();
}, ms );
});
}
You would then call this from your handler, providing the agent, the message, and how many milliseconds to wait to reply:
function welcome( agent ){
return respondSlowly( agent, `Hi there, slowly`, 2000 ); // Wait 2 seconds to reply
}

How to deal with acks for asynchronous types of tasks

Right now I have a RabbitMQ queue setup, and I have several workers that are listening for events pushed onto this queue.
The events are essentially string urls (e.g., "https://www.youtube.com"), and it'll be processed through puppeteer.
What I'm wondering is given that puppeteer is asynchronous, is there a way for me return an ack once I've finished all the asynchronous stuff.
Right now, I think my workers listening to the queue are hanging because the ack isn't being fired.
edit -- code below is what I pretty much call within the consume part of rabbitmq. Because this is async, it kinda just goes past this operation and just immediately acks.
(async () => {
const args = {
evaluatePage: (() => ({
title: $('title').text(),
})),
persistCache: true,
cache,
onSuccess: (result => {
console.log('value for result -- ', result.result.title);
}),
};
// we need to first setup the crawler
// then we can start sending information to it
const crawler = await HCCrawler.launch(args);
crawler.queue(urls);
await crawler.onIdle();
await crawler.close();
})();

Where to Put subscription.pull when want to get the publish data Google Cloud pub/sub NODE JS

So i've tried to develop some pub/sub system based on node js
i am using express post request to publish the data that i wanted. it's send the data well, but my question is where should i put my code for the subscription
Right now i put the code at the root of my file like this
pubSub.subscribe()
.then(({results, subscription}) => {
results[0].data.forEach((item) => {
let key = ['UserId', fakeId(1, 100), 'FeedId', fakeId(100, 200), 'plugin', fakeId(1, 100)]
upsert(key, item, () => {
console.log('Sync Success')
console.log(item)
}, error => console.error(error))
})
subscription.ack(results.map((result) => result.ackId));
})
.catch(error => console.error(error))
i have some helper to subscribe like this
function subscribe () {
const subscription = pubSub.subscription('plugin_subscription')
return new Promise ((resolve, reject) => {
return subscription.pull((error, results) => {
console.log('ini ke trigger')
if (error) reject(error)
resolve({results, subscription})
})
})
}
well it's kind of only work once. if i publish message i dont' have any response log from the subscriber, but if i restart the node js server my log is show that i successfully receive the data and could proceed to the next step.
Am i doing something wrong here?
thanks a lot man
A couple ideas:
You're using promises to handle received messages. A promise on its
own can only be triggered once - to trigger it multiple times, you'd
need some sort of loop or recursive call.
Try using event
handlers (see this example) instead of promises - those should trigger every time an
event occurs without any additional looping or recursion. Note that for this example, you'll need to remove the code that removes the messageHandler listener.
Hopefully this helps!

Resources