NestJs Cron Service - cron

I am trying to create a Schedule service using nestJs' Cron decorator
I have a Cron-decorated method below:
#Cron(CronExpression.EVERY_5_SECONDS)
triggerDataloaderCron() {
this.logger.debug('called every 10 seconds');
return this.healthService.getPCFHealth();
}
And this cron job calls a method in another service, which is shown below
getHealth() {
//code to form up an endpoint, saved as the variable fullUrl
//Does not come into this block
return this.httpService.get(fullUrl).pipe(
map((axiosResponse: AxiosResponse) => {
return axiosResponse.data;
}),
catchError((err) => {
console.log("in error", err);
throw new CustomException(ExceptionConstants.EurekaConnectionException);
})
);
}
When the cron job runs, i am able to enter the getHealth() method, but the this.httpService etc... block of code does not run.
Any suggestions on how this can be achieved? Or if I am going about this the wrong way?
Thanks!

The getHealth method returns an Observable. An observable does not execute unless there is at least one subscriber.
In your cron method, add a subscription as follows:
this.healthService.getPCFHealth()
.subscribe(response => console.log(response))
Since the cron method executes at regular intervals, I don't think you need to return a value from it.

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!

Asynchronous Easy Table scripts in Azure

In Azure Portal, I'm modifying the scripts of an Easy Table, and I'm having trouble figuring out how to properly return a response to a client within a modified script. This is using the node package azure-mobile-apps
Just as a simple example, let's say I had a table that I was modifying the 'insert' function on, like so:
function getUserHeader(context) {
return context.req.headers['user-id'];
}
table.insert(function (context) {
context.item._user_id = getUserHeader(context);
return context.execute();
});
Now this is all fine, works perfectly as expected, item on the table ends up with correct _user_id and everything.
But let's say, for whatever reason, I had to make getUserHeader asynchronous and return a promise (maybe I want to verify a token or check something on a related table before executing the context). Here's what the above code might look like async:
function getUserHeader(context) {
return new Promise(function(resolve, reject){
resolve(context.req.headers['user-id']);
});
}
table.insert(function (context) {
getUserHeader(context)
.then(function(uid) {
context.item._user_id = uid;
return context.execute();
})
});
Now it works on one level: context.execute does run, and the record does get created, with the correct _user_id. HOWEVER the http call the client made never gets a response. Normally the http response returns with the item that cot added to the table (in the case of insert), but not here.
What's the proper way to add in asychronous functions to the workflow of the easy table scripts?
You missed return keyword when you call a Promise function.
This would work if you change it to:
table.insert(function (context) {
return getUserHeader(context).then(function(uid) {
context.item._user_id = uid;
return context.execute();
})
});

Node.js agenda: how to retry jobs after failure?

Using Agenda, is it possible to set jobs to retry after several times after failure?
If it's a repeating job, you can change the nextRunAt value when it fails and it will run again:
agenda.on("fail", async (error, job) => {
const nextRunAt = new Date();
job.attrs.nextRunAt = nextRunAt;
await job.save();
});
if it's a scheduled job (meaning it doesn't repeat, the above code won't work. You have to create a new job.
agenda.on("fail", async (error, job) => {
if(job.attrs.repeatInterval) {
// create a new job and pass it job.attrs.data
}
});
Retry is not directly supported as an option, but it has a simple workaround by setting the failed jobs nextRunAt to a future time.
Refer this article :
https://crossbrowsertesting.com/blog/product-update/task-scheduling-with-agenda/

Meteor method doesn't work

Assume that I have a Collection called Tasks which has few tasks in it.I call a method to return a task array to the user but for some reason it doesn't return anything.
Here is a code for example:
if (Meteor.isClient) {
// This code only runs on the client
Template.body.helpers({
tasks: function () {
// Show newest tasks first
Meteor.call("getTasks", function(error, result) {
return result; // Doesn't do anything..
});
}
});
}
Meteor.methods({
getTasks: function() {
return Tasks.find({}, {sort: {createdAt: -1}});
}
});
Any ideas why when I call the method it doesn't return anything?
Tasks.find() returns a cursor, which makes no sense to transmit to the client via DDP.
You probably mean to return Tasks.find().fetch(), but that defeats the purpose of Meteor's very nice data synchronization mechanism.
Have you read Understanding Meteor's publish/subscribe?

NightmareJS screenshot callback

I'm using this framework to make screenshots of several urls. The process of taking the screenshot is async, and the method does not provide a way to execute a callback, and I want to execute a callback when each screenshot is made on this script:
nightmare = new Nightmare();
urls.forEach(function (url) {
nightmare.goto(url).screenshot(path);
});
nightmare.run(function () {
console.log('finished all');
});
Any ideas how can I do this?
I found a way to do this, with the "use" method for executing plugins.
nightmare = new Nightmare();
urls.forEach(function (url) {
nightmare.goto(url).screenshot(path).use(function () {
console.log('finished one');
});
});
nightmare.run(function () {
console.log('finished all');
});
This appears to be the purpose of the run() method. You probably want to set up and run each screenshot within the loop, since the screenshot() method relies on the phandomjs method render(), and render() is strictly synchronous (at least as of a year ago):
urls.forEach(function (url) {
nightmare = new Nightmare();
nightmare.goto(url).screenshot(path).run(function(err, nightmare) {
console.log('this executes when your screenshot completes');
// run() appropriately tears down the nightmare instance
});
});
console.log('finished all');
You don't gain any asynchronous benefits from setting up all the screenshots at once, and "finished all" is guaranteed to only run once all screenshots have been rendered.
Alternatively, in the nightmarejs source, it looks like screenshot() does take a second done parameter that appears to be a callback, but it passes it directly into the phantomjs render() method, and as seen in the above link there was some resistance to allowing that method to take a callback.

Resources