Google sheets script - mail onedit - google-docs

A couple people use one sheet and I want to be noticed by mail every time that an edit is made (at once user makes around 20 edits and I want receive only one mail).
I wrote a code:
var a;
function onOpen(){
a = 0;
}
function onEdit(){
a++;
}
function sendMail(){
if(a > 0){
GmailApp.sendEmail('xxx#gmail.com', 'aaa', 'sss ');
a = 0;
}
}
function onOpen is triggered by opening the document
function onEdit is triggered by any edit in a spreadsheet
function sendMail is triggered every 5min
I identified that function onOpen assignes 0 to var a only in the function and in sendMail var a is identified as NaN. How can I solve the problem?

I just want to add that I tried to use built-in notifications, but for some reason it didn't work correctly. I received a lot of email notifications that were triggered for unknown reason (around 60 daily).
Anyone? Plsss...

Related

Automatic run function daily at specific time

I'm doing a school project about CMS System to help operate my school website. It use 3 database:
MongoDB (Head database, store all information)
Redis (Store the menu of website)
Elasticsearch (Store posts)
Currently when I insert/edit/delete data, I also insert/edit/delete to a related database. But my mentor want me to write a function that let's system auto sync data between those 3 database at a specific time (user can choose when).
My server uses Node JS to operate, this requirement is new for me, never heard about it before. My new approach is:
Add 1 flag to database field
Select all rows which contain flag == true.
Sync data
But I don't know how to auto run above function at a specific time. I hope you guys can help me to optimize my new flow and solve the sync problem.
Thank you all !!!
Edit 1: Change tittle.
Edit 2: I found a solution from this topic: Running a function everyday midnight, is there anyway to re-run this function if error occur when sync data. Something like this:
function syncDataAtMidNight(){
var now = new Date();
var night = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate() + 1, // the next day, ...
0, 0, 0 // ...at 00:00:00 hours
);
var msToMidnight = night.getTime() - now.getTime();
setTimeout(function() {
// is this a correct way to loop, in case of error when sync ???
myFunctionSync(err, resp) {
if(err){
myFunctionSync();
} else {
changeFlagToFalse();
syncDataAtMidNight();
}
}
}, msToMidnight);}
You should consider to use cron, he have the significant advantage to be at system level, he can get the code error return and mostly launch/relaunch node if necessary.

node delay execution - What's right/wrong with it?

At first, I'm a newbie without experience in node js and would like to learn more. I wrote a delay function and I'm interessted, what you as a javascript professional think about it. What is good or bad on it and why?
I try to write a bot. It has 2 function. Function 1 starts function 2. But function 2 shall not start direct afterwards. It has to start with a delay.
Of course I made research for my topic and have found stuff like this:
How Can I Wait In Node.js (Javascript), l need to pause for a period of time
How to create a sleep/delay in nodejs that is Blocking?
Unfortunately I'm not able to understand and use it. Therefore I made my own try. It works on my computer, but should I bring it on a server?
//function 1 (example)
function start(){
...;
delay(2500, 'That could be an answer');
}
//Delay
function delay(ms, msg){
var started = new Date();
var now;
var diff = 0;;
while(diff < ms){
now = new Date();
diff = now - started;
console.log('Diff time: '+diff);
}
console.log('Delay started at: '+started);
console.log('Now time: '+now);
console.log('ms time: '+ms);
console.log('While loop is done.');
answer(msg);
}
//function 2 (example)
function answer(msg){
...
}
Thank's!
This is blocking.. your event loop will block executing this code. No other work will be done throughout the 2500 ms interval except for busy waiting inside the loop.
I'm not sure why you would want to do this. What you can do if you want to start function 2 at some point after function 1 is use setTimeout. This way, function 2 will be started after at least the time that you pass as argument to the setTimeout function while allowing other code to execute and not blocking the node event loop.
setTimeout(function(){
answer(msg);
}, 2500);
it does not work nevertheless. My delay time is more than an hour. Bute function 2 is executed after a couple of seconds.
setTimeout(function(){
answer(msg);
}, Math.floor(Math.random()*1000*87));
You can use bluebird promises with .delay to maintain your code more clean.
http://bluebirdjs.com/docs/api/promise.delay.html
Make your start function a promise then:
start().delay(2500).then(function (result) {
// result = start function return statment
});

Make an event handler seamless?

I have written an event handler under Excel online add-in. It is activated by a button activate, then when a user clicks on another cell or range, the address will be written on a text area myTextArea. The whole thing works.
However, once a new cell is selected, a green loading symbol is shown near the focus; WORKING... is shown on the bottom of Excel; it takes almost 0.5 second.
I am just surprised that it takes time for such a simple action. Does anyone know if it is possible to make this event hander faster? Otherwise, is there any other mean than event handling to make this seamless?
(function() {
"use strict";
Office.initialize = function(reason) {
$(document).ready(function() {
app.initialize();
$('#activate').click(addSelectionChangedEventHandler);
});
}
;
function addSelectionChangedEventHandler() {
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged, MyHandler);
}
function MyHandler(eventArgs) {
doStuffWithNewSelection();
}
function doStuffWithNewSelection() {
Excel.run(function(ctx) {
var selectedRange = ctx.workbook.getSelectedRange();
selectedRange.load(["address"]);
return ctx.sync().then(function() {
write(selectedRange.address)
})
}).then(function() {
console.log("done");
}).catch(function(error) {
...
});
}
function write(message) {
document.getElementById("myTextarea").value = message;
}
})();
What you're seeing is network lag. The selection changed event -- once registered -- originates on the server, and triggers the code if Office.js that fires your event handler. Your event handler, in turn, creates a local request for getting the selection Range object and its address, sends it over to the server as part of ctx.sync(), and then waits to hear back from the server before firing the .then.
There's not anything you can do to optimize this flow -- you will pay a pretty high per-transaction cost on Excel Online, and event handlers only add one extra step to that cost. On the other hand, the good news is that the Excel.run/ctx-based model does allow you to batch multiple requests into one, drastically reducing the number of roundtrips that would otherwise be required. That is, fetching the values of 10 different ranges is almost identical in speed to fetching just one; whereas it would be 10 times more expensive if each call were made individually.
Hope this helps!
~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT

Meteor.setTimeout is not causing delay

I am creating my first Meteor app with the Spheron smart package. I can control he sphero ok and change it's colors but I'm trying to create a delay in between the color change.
Here is my code:
function makePrettyLights(sphero,color){
var colors = [];
colors['red'] = '0xB36305';
colors['green'] = '0xE32017';
colors['blue'] = '0xFFD300';
console.log(color);
var spheroPort = '/dev/tty.Sphero-OBB-RN-SPP';
var timer = 2000;
Meteor.setTimeout(function(){
sphero.on('open', function() {
sphero.setRGB(colors[lineName], false);
});
sphero.open(spheroPort);
},2000);
}
This function is being called from in a loop. I havent included the loop at it involves me parsing some xml and other bits but it works.
if (Meteor.isServer) {
/**** Loop Code Here ****/
makePrettyLights(sphero,color)
/****End Loop Code ****/
}
I have also tried setting the timeout wrapper around the function where it is called instead of inside it.
But basically they all run at the end of my code at the same time.
I20140806-09:49:35.946(1)? set color
I20140806-09:49:35.946(1)? set color
I20140806-09:49:35.946(1)? set color
The problem is most probably in your loop. I assume it's a pretty standard for loop, in which case such behavior is expected. When you call:
for(var i=0; i<5; ++i) {
setTimeout(someFunction, 2000);
}
the setTimeout method will be called 5 times in a row in a single moment. This means that someFunction will be called 5 times in a row after 2000 miliseconds.
Your sphero variable is scoped outside the timeout. So every time a connection is opened the previously added callbacks will fire at the same time since you're just adding on to globally scoped sphero variable.
Try defining sphero (not currently shown with your code above) inside the Meteor.setTimeout callback instead of outside of it.

How do I execute a piece of code no more than every X minutes?

Say I have a link aggregation app where users vote on links. I sort the links using hotness scores generated by an algorithm that runs whenever a link is voted on. However running it on every vote seems excessive. How do I limit it so that it runs no more than, say, every 5 minutes.
a) use cron job
b) keep track of the timestamp when the procedure was last run, and when the current timestamp - the timestamp you have stored > 5 minutes then run the procedure and update the timestamp.
var yourVoteStuff = function() {
...
setTimeout(yourVoteStuff, 5 * 60 * 1000);
};
yourVoteStuff();
Before asking why not to use setTimeinterval, well, read the comment below.
Why "why setTimeinterval" and no "why cron job?"?, am I that wrong?
First you build a receiver that receives all your links submissions.
Secondly, the receiver push()es each link (that has been received) to
a queue (I strongly recommend redis)
Moreover you have an aggregator which loops with a time interval of your desire. Within this loop each queued link should be poll()ed and continue to your business logic.
I have use this solution to a production level and I can tell you that scales well as it also performs.
Example of use;
var MIN = 5; // don't run aggregation for short queue, saves resources
var THROTTLE = 10; // aggregation/sec
var queue = [];
var bucket = [];
var interval = 1000; // 1sec
flow.on("submission", function(link) {
queue.push(link);
});
___aggregationLoop(interval);
function ___aggregationLoop(interval) {
setTimeout(function() {
bucket = [];
if(queue.length<=MIN) {
___aggregationLoop(100); // intensive
return;
}
for(var i=0; i<THROTTLE; ++i) {
(function(index) {
bucket.push(this);
}).call(queue.pop(), i);
}
___aggregationLoop(interval);
}, interval);
}
Cheers!

Resources