I am writing a NodeJS push notification server for iOS and Android. Currently, once I get the device tokens I save them in a local MongoDB database and then fire notifications when there is a change. The problem is, that the database where the "change"(information is added) happens isn't my own. It's a third party's server. So the way I am aware of the change in the server is by using an API provided by the third party. My current solution is using setTimeout to make a request every X minutes to check for a change and then firing a notification based on that. The shorted interval is 10 minutes and the longest one is 1 hour. I change the intervals
dynamically through out the day based on time. My question(s) is (are),
1.) Is the setTimeout method the best possible solution to this problem? If not what else can I use?
2.) Is there any way I can implement Web Sockets in this scenario?
3.) If setTimeout is the only option, what kind of problems should I expect to run into?
This what the current function looks like
function start_notifications_server_driver() {
if(current_user_info.num_sent <= current_user_info.frequency){
//I removed the interval object on here because it's quite large and would take up space here
for(var i = 0; i < intervals.length; i++){
if(check_if_time_between(intervals[i])){
if(dev_mode) console.log("Returned true for", intervals[i]);
temp_interval = intervals[i].frequency;
break;
}
}
check_updates_for_channels_driver();
setTimeout(start_notifications_server_driver, temp_interval);
console.log("Time Interval changed to now", temp_interval);
}
}
Related
I'm creating a chrome extension. I need to know when a user clicked on a specific button how many mili seconds will take long, to receive that command to website server. I have a web Worker that is connected to that website too. Could I get the exact time when a button clicked to when data received by website's server? It doesn't matter how many mili seconds take that the respond back to me, the time of receiving request to server after click is mu issue now. can someone help me please?
I'm looking for javascript code to get the time distance between button clicked and received that by website's server.
It is easy to get the time when button is clicked by finding that button and attaching an event handler on it, that calls performance.now()
const t0 = 0;
document.getElementById('buttonId').addEventListener('click',() => {
t0 = performance.now();
});
Detecting when the server response is received is not trivial. You might need to use the chrome.webRequest api.
Alternatively, a simpler way would be to look for side-effects of the request, that happen in the DOM. (A loader appearing and disappearing, data rows appearing, button being disabled and re-enabled, etc).
You can either poll for these changes, or use the mutationObserver api to detect when elements containing expected attributes are available in the DOM.
Let's say you are polling for the button being re-enabled, every 10ms:
const t1 = 0;
const interval = window.setInterval(() => {
if (!document.getElementById('buttonId').getAttribute('disabled')) {
t1 = performance.now();
requestTime = t1 - t0;
console.log(requestTime);
window.clearInterval(interval);
}
},10);
I created a real-time clock that updates every second. When I run it locally I see no errors. However when I uploaded it to my web host I saw a lot of error messages in the console every time the AJAX code runs.
I think that's the reason why web host suspended my site, telling that my site has performed too many requests.
Here is my code:
$(document).ready(function() {
setInterval(function() {
$('#time').load('timewithdate.php')
}, 1000);
setInterval(function(){
$('#time2').load('time.php')
}, 1000);
})
I'm not sure what kind of answer you are looking for. Your code is a certain way to kill a server: it's making 2 calls to the server every second for each client (read more about DDOS). There is no need to make a server call, just use javascript to get the current time and format it the way you want. You can have something like this:
$(document).ready(function() {
setInterval(function() {
let curTime = new Date();
let date = curTime.toLocaleDateString();
let time = curTime.toLocaleTimeString();
$('#time').text(date + " " + time);
$('#time2').text(time);
}, 1000);
})
The error is because you have effectively DDOS'd your own server with 2 requests every second * number of concurrent clients. I would strongly suggest you remove these AJAX requests and perform the countdown on the client side.
If you're trying to keep the clocks in sync with server time, get the time from the server when the page loads, then add seconds to it on the client side. Do not use AJAX for this, and do not use AJAX polling in future. It's an anti-pattern.
When my system goes to hibernate mode, the javascript timer stop the countdown and when it comes back it continue with the countdown.
But my problem is that I'd like the countdown to continue when my system goes to hibernate mode. Is there any solution / workaround to achieve that?
This isn't really a javascript issue.
When you close the lid, your laptop is hibernating, meaning the CPU is switched off and cannot calculate things.
You have three options
1) Make the laptop stay on when closing the lid, or don't close the lid
2) Stop doing timer tasks client side, and instead simply start a timer on the server. Depending on what you are trying to achieve, this may or may not be relevant, but it is the only way to know the user will keep their lid open/browser open/machine on etc.
3) Re-work your code so instead of using a timer that says "wait ten seconds", you instead set it to use absolute times, something like the following (which is vague pseudo-code to demonstrate what I mean, not a working solution)
var targetTime;
var running = false;
startTimer(timeInSeconds)
{
targetTime = now() + timeInSeconds;
running = true;
}
while(running)
{
if(now() > targetTime)
{
doTimerThings();
running = false;
}
}
This will not get the timer precisely right, but will fire as soon as possible after the machine is started again. You can change your logic to suit how you wish to handle this (eg handling things differently if the timer is being fired late)
It won't help if you need to fire the timer at exactly the interval... but that simply isn't possible when the computer is off.
I'm using PHP over IIS 7.5 on Windows Server 2008.
My web application is requesting repeatedly with Ajax in the background 3 different JSON pages:
page 1 Every 6 seconds
page 2 Every 30 seconds
page 3 Every 60 seconds
They retrieve data related with the current state of some tables. This way I keep the view updated.
Usually I have no much trouble with it, but lately I saw my server saturated with hundreds of unanswered requests and I believe the problem can be due to a delay in one of the request.
If page1, which is being requested every 6 seconds, needs 45 seconds to respond (due to slow database queries or whatever), then it seem to me that the requests start getting piled one after the other.
If I have multiple users connected to the web application at the same time (or with multiple tabs) things can turn bad.
Any suggestion about how to avoid this kind of problem?
I was thinking about using some thing such as ZMQ together with Sockets.io in the client side, but as the data I'm requesting doesn't get fired from any user action, I don't see how this could be triggered from the server side.
I was thinking about using some thing such as ZMQ together with Sockets.io in the client side...
This is almost definitely the best option for long-running requests.
...but as the data I'm requesting doesn't get fired from any user action, I don't see how this could be triggered from the server side.
In this case, the 'user action' in question is connecting to the socket.io server. This cut-down example is taken from one of the socket.io getting started docs:
var io = require('socket.io')(http);
io.on('connection', function(socket) {
console.log('a user connected');
});
When the 'connection' event is fired, you could start listening for messages on your ZMQ message queue. If necessary, you could also start the long-running queries.
I ended up solving the problem following the recommendation of #epascarello and improving it a bit if I get no response in X time.
If the request has not come back, do not send another. But fix the serverside code and speed it up.
Basically I did something like the following:
var ELAPSED_TIME_LIMIT = 5; //5 minutes
var responseAnswered = true;
var prevTime = new Date().getTime();
setInterval(function(){
//if it was answered or more than X m inutes passed since the last call
if(responseAnsswered && elapsedTime() > ELAPSED_TIME_LIMIT){
getData()
updateElapsedTime();
}
}, 6000);
function getData(){
responseAnswered = false;
$.post("http://whatever.com/action.json", function(result){
responseAnswered = true
});
}
//Returns the elapsed time since the last time prevTime was update for the given element.
function elapsedTime(){
var curTime = new Date().getTime();
//time difference between the last scroll and the current one
var timeDiff = curTime - prevTime;
//time in minutes
return (timeDiff / 1000) / 60;
}
//updates the prevTime with the current time
function updateElapsedTime(){
prevTime = new Date().getTime();
}
This is a very bad setup. You should always avoid polling if possible. Instead of sending request every 6 seconds from client to server, send data from server to the clients. You should check at the server side if there is any change in the data, then transfer the data to the clients using websockets. You can use nodejs at the server side to monitor any changes in the data.
Basically, I am designing a quiz application with limited time. Use selects answer to a question and the next question loads using an Ajax request. All questions must be answered within a time frame of, say 2 minutes.
A clock ticks away to show how much time is left and as soon as it hits 0, results are shown. Now since the timer will be implemented using window.setTimeout(), it is possible that the value of timer variable be modified using an external bookmarklet or something like that. Anyway I can prevent this? I think this is implemented on file sharing sites like megaupload. Any forgery on the timer variable results in request for file being rejected.
Have .setTimeout() call an AJAX method on your server to synch time. Don't rely on the client time. You could also store the start time on the server for a quiz, and then check the end time when the quiz is posted.
You need to add a validation in your server side. When the client want to load the next question using an Ajax request, check whether deadline arrived.
The timer in client side js just a presention layer.
If the function runs as a immediately called function expression, then there are no global variables and nothing for a local script to subvert. Of course there's nothing to stop a user from reading your code and formulating a spoof, but anything to do with javascript is open to such attacks.
As others have said, use the server to validate requests based on the clock, do not rely on it to guarantee anything. Here's a simple count down that works from a start time so attempts to dealy execution won't work. There are no global variables to reset or modify either.
e.g.
(function (){
// Place to write count down
var el = document.getElementById('secondsLeft');
var starttime,
timeout,
limit = 20; // Timelimit in seconds
// Function to run about every second
function nextTick() {
var d = new Date();
// Set start time the first time
if (!starttime) starttime = d.getTime();
var diff = d.getTime() - starttime;
// Only run for period
if (diff < (limit * 1000)) {
el.innerHTML = limit - (diff/1000 | 0);
} else {
// Time's up
el.innerHTML = 0;
clearTimeout(timeout);
}
}
// Kick it off
timeout = window.setInterval(nextTick, 1000);
}());