I have been working on a custom node for what seems like an eternity (worse it is yet another scheduling node . I have it close to where I want it but have come across one interesting problem.
The node uses a callback function to fire time based events. Inside the callback function I don't do anything special, just send on the message with node.send(msg). However in the most basic test configuration (scheduling one event after another), only the LAST firing of the callback sends the msg.
I know the previous fired events contain the msg because it is output to the console correctly at the correct time.
I am hoping I have left something simple out like node cleanup etc, but any clues as to where to start looking would be appreciated.
Hey Bob,
that should work what you are doing. Perhaps you should share a code snippet ... Here you can see that I do something similar in my node-red-contrib-msg-resend node. For example:
var yourTimerId = setInterval(function() {
node.send( {payload: "test"});
}, 5000);
Make sure that you create a NEW message every time the callback is triggered! Because when you resend the same message over and over again, you will get weird results (as soon as the next nodes in the flow start changing the content of that single message over and over again)...
And don't forget to stop your timer, as soon as your node is cleaned up:
Thanks for the tips Bart. Unfortunately I'm still at a loss to understand where I have made the mistake, or perhaps I am misunderstanding something fundamental regarding sending messages.
A code snippet probably won't help you much but it will clearly demonstrate the issue:
var j = schedule.scheduleJob(jb, date, function () {
var id_status = context.get('cancel-date');
console.log('single date - ', jb);
console.log('message = ', msg);
send(msg);
});
What I don't understand is the output from the console is always correct. There is a msg displaying the correct msg_id and info when the event is fired. There is just no output at the debug node from send(msg).
Maybe a silly question, but you just call send(msg);. Where/how is send defined in your code?
The send function is available on the enclosing function that defines your node. So unless you do something like let send = this.send; beforehand, that code will not work, because send is not in the closure of your callback function.
Thinking even further, just calling send() may mess up the send function itself, because this will not be bound to the node function. You'd have to do something like
let node = this;
var j = schedule.scheduleJob(jb, date, function () {
var id_status = context.get('cancel-date');
console.log('single date - ', jb);
console.log('message = ', msg);
node.send(msg);
});
Working from your example, your code should look something like the following. Unless I completely misunderstand what your node is supposed to do.
function MyNode(config) {
RED.nodes.createNode(this, config);
const node = this;
var j = schedule.scheduleJob(jb, date, function () {
var id_status = context.get('cancel-date');
let msg = {payload: 'foo'};
console.log('single date - ', jb);
console.log('message = ', msg);
node.send(msg);
});
}
Another question... where do you get the message object from? Or are you trying to schedule from within a on('input') event??? That would be a completely different case.
Ok, so it is a fairly basic daily scheduler node using the node-schedule node. I am aware that that particular nodejs node does have a few bugs but se la vì.
Either the schedule can be passed in, or created in the node's editor. I then add msg.alarm_date.xxx which forms the scheduled date for the callback function to fire.
Okay... so it isn't the thing I suspected regarding the binding of this.
But I see that you send the same message instantly and reuse it in your callbacks. By resending the same message reference you are in for trouble. It may work in simple cases, but since your are setting lots of message properties and rely on them for your scheduling, you should clone the message using RED.util.cloneMessage(msg);. Otherwise the message will be modified by subsequent nodes in the meantime until your callback gets fired.
I would create the clone early in your on('input') function and use that clone in the scheduler callback.
The original message can then be sent instantly (the last node.send(msg); in your code)
So the test scenario is (using the nodes editor), set a schedule and deploy. Set another schedule and deploy. The first schedule msg gets sent to debug, the second (third etc) does not.
If you are still interested in solving the mystery I will stick my node up on github.
Another piece to the puzzle. The order in which the events are deployed (as per my testing scenario) affects which msg gets sent to debug (ie last deployed event will trigger debug only).