How to Long Poll in NodeJS / Javascript? - javascript

Just to be clear my understanding of long polling is that you make request to a server on a time interval.
I am trying to implement a bitcoin purchasing system that checks the blockchain for change in my wallets balance. I know there are websockets that do this but I have to wait for 1 confirmation to receive an update and the REST API offers more flexibility, so I would just prefer to make a request to the server every 5 seconds or so and check each response for a change in my balance then go from there.
The issue is I can't seem to figure out how to do this in NodeJS. Functionially this is how I imagine my code.
Get current balance (make request)
Get current balance again (make request)
Check if there is a difference
**If not**
wait 5 seconds
Get current balance
Check for difference
repeat till different (or till timeout or something)
If different
do some functions and stop checking balance.
I've been trying to do each step but I've gotten stuck at figuring out how to create a loop of checking the balance, and stopping the loop if it changes.
My original thought was to use promises and some for loops but that doesn't materialize.
So now I am asking for your help, how should I go about this?

One way to do this would be to setup a setInterval timer to kickoff a request every x seconds. By setting some logic after the response you can then choose to de-reference the timer and trigger another function. Here's a snippet. You'll notice I set a variable to reference the timer, and then de-reference it by setting it to null, where then the GC is smart enough to release. You may also use the 'clearTimeout' function, which is perhaps the better way to go.

Related

how to bypass firebase functions cold start

I am using the firebase Stripe API, and what is happening is my app doesn't have a lot of traffic yet, nor will it for a little while. Firebase decided, after 2-3 minutes of no invocations on the function, it goes into cold start mode. This is unfortunate because it means my wait time from when a new user hits register, and goes to the checkout page, it is like 8 seconds. How horrendous is that!
Anyways, does anyone know a way around this, maybe setting a script to run in the background at all times, or something I can do from inside firebase?
One way to help is to add a "cold-start" command to the Cloud Function (i.e. a "no-op" invocation/call), and invoke it when your user starts the checkout process (before collecting any information). If the User doesn't complete check-out, no-harm-no-foul; if they do, the cloud function has already been started.
Update 2020-01-01:
Firebase now allows you to designate for each function, in the console, a minimum (and/or maximum) number of invocations - i.e. keeping functions in memory. A single active function costs about $0.33 to $0.50 per month - a fairly low (but not zero) cost for keeping cold starts down...

NodeJS - Multiple Timeouts vs one Interval for sessions in bots

I would like the messenger bot to notify the user that their session ended if they did not write/give input to the bot for some time. In order to do so, I first thought about using setTimeout() for each user which will reset upon activity. But that means if there will be 100 active users, there will be 100 Timeouts at the same time.
I wanted to know, if having one Interval instead that checks through each user`s session end timestamp every 30-60 seconds a better approach? The active users are stored in memory.
setTimeout is more precise in your case: each session will be ended independently and closer to the time it was supposed to end. It will also spread the activity more evenly. Since JS is single-threaded, the timeouts will not fire in parallel, even though there will be hundreds of them at the same time.
setInterval will create spikes of activity every 30-60 seconds, and will sometimes let the sessions stay alive longer than they should.
As per the cost of multiple timeouts running at the same time, please see this answer.

Call NodeJs function at a specific moment in time

Is there a way to automate functions and call them at a specific mooment in time with Node.Js ? More precisely, I would like to create a reminder with node js. When I receive the date from the user, I have to send notification to remind him/her of something.
I know setTimeout() function but is it really good idea when I have large database of users ?
Thank you.
You can use setTimeout() and keep all the work inside your server, but for a large number of users, you would not necessarily want to set a timeout for every single user. All you really need is a single timeout for the next user that needs to be notified. When that timer fires, you then set a timer for the next user that needs to be notified and so on.
This can be done with an array of objects that you sort by the notification time. Each time you add something to the array, you cancel your current timer, add the new notification to the array, sort the array and set a timer for the earliest notification.
When a timer fires, you remove that item from the array and schedule the next one.
And, since you likely want this to survive a server restart, you save the notification array (probably in JSON format) to a file or to a database each time you modify it so you can reload that data upon a server restart.
FYI, there are scheduling modules for node.js that already offer this type of functionality if you'd prefer to pick up code someone else has already written.
Examples of some of these modules:
node-cron
agenda
node-schedule
What you are looking for is called a Scheduler or a cron job (its origin is from Linux OS).
In NodeJS you can find the node-schedule that implement the same idea.

Access same setTimeout() instance from multiple Node.js instances

Our API needs to send data to Zapier if some specific data was modified in our DB.
For example, we have a company table and if the name or the address field was modified, we trigger the Zapier hook.
Sometimes our API receives multiple change requests in a few minutes, but we don't want to trigger the Zapier hook multiple times (since it is quite expensive), so we call a setTimeout() (and overwrites the existing setTimeout) on each modify requests , with a 5000ms delay.
It works fine, and there are no multiple Zapier hook calls even if we get a lot modify requests from client in this 5000ms period.
Now - since our traffic is growing - we'd like to set up multiple node.js instances behind some load balancer.
But in this case the different Node.js instances can not use - and overwrite - the same setTimeout instance, which would cause a lot useless Zapier calls.
Could you guys help us, how to solve this problem - while remaining scalable?
If you want to keep a state between separate instances you should consider, from an infrastructure point of view, some locking mechanism such as Redis.
Whenever you want to run the Zapier call, if no lock is active, you set one on Redis, all other calls won't be triggered as it is locked, whenever the setTimeout callback runs, you disable the Lock.
Beware that Redis might become a SPOF, I don't know where you are hosting your services, but that might be an important point to consider.
Edit:
The lock on Redis might have a reference to the last piece of info you want to update. So on the first request you set the data to be saved on Redis, wait 5 seconds, and update. If any modifications were made in that time frame, it will be stored on Redis, that way you'll only update on 5 second intervals, you'll need to add some extra logic here though. Example:
function zapierUpdate(data) {
if (isLocked()) {
// Locked! We will update the data that needs to be saved on the
// next setTimeout callback
updateLockData(data);
} else {
// First lock and save data.
lock(data);
// and update in 5 seconds
setTimeout(function(){
// getLockData fetches the data on Redis and releases the lock
var newData = getLockData();
// Update the latest data that might have been updated.
callZapierNow(newData);
},5000);
}
}

Batch Backbone.js events?

My app's framework is built around collapsing backbone models sending the data via websockets and updating models on other clients with the data. My question is how should I batch these updates for times when an action triggers 5 changes in a row.
The syncing method is set up to update on any change but if I set 5 items at the same time I don't want it to fire 5 times in a row.
I was thinking I could do a setTimeout on any sync that gets cleared if something else tries to sync within a second of it. Does this seem like the best route or is there a better way to do this?
Thanks!
i haven't done this with backbone specifically, but i've done this kind of batching of commands in other distributed (client / server) apps in the past.
the gist of it is that you should start with a timeout and add a batch size for further optimization, if you see the need.
say you have a batch size of 10. what happens when you get 9 items stuffed into the batch and then the user just sits there and doesn't do anything else? the server would never get notified of the things the user wanted to do.
timeout generally works well to get small batches. but if you have an action that generates a large number of related commands you may want to batch all of the commands and send them all across as soon as they are ready instead of waiting for a timer. the time may fire in the middle of creating the commands and split things apart in a manner that causes problems, etc.
hope that helps.
Underscore.js, the utility library that Backbone.js uses, has several functions for throttling callbacks:
throttle makes a version of a function that will execute at most once every X milliseconds.
debounce makes a version of a function that will only execute if X milliseconds elapse since the last time it was called
after makes a version of a function that will execute only after it has been called X times.
So if you know there are 5 items that will be changed, you could register a callback like this:
// only call callback after 5 change events
collection.on("change", _.after(5, callback));
But more likely you don't, and you'll want to go with a timeout approach:
// only call callback 30 milliseconds after the last change event
collection.on("change", _.debounce(30, callback));

Categories