Javascript 功能未按时运行
我试图通过在将连接到大型监视器的raspberry pi上运行nodejs应用程序来创建度量仪表板 应用程序每小时查询一次SQL server。当我在mac上运行它时,效果非常好,但当我在raspberry上运行它时,它似乎运行了一两次,然后停止。我已经在覆盆子上禁用了屏幕保护程序,但我不知道如何调试它。我将包含完整的代码,因为我不确定是tick()函数本身还是其他什么Javascript 功能未按时运行,javascript,node.js,raspberry-pi3,raspbian,xtuple,Javascript,Node.js,Raspberry Pi3,Raspbian,Xtuple,我试图通过在将连接到大型监视器的raspberry pi上运行nodejs应用程序来创建度量仪表板 应用程序每小时查询一次SQL server。当我在mac上运行它时,效果非常好,但当我在raspberry上运行它时,它似乎运行了一两次,然后停止。我已经在覆盆子上禁用了屏幕保护程序,但我不知道如何调试它。我将包含完整的代码,因为我不确定是tick()函数本身还是其他什么 "use strict"; var fs = require('fs'); var readline = require('
"use strict";
var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
var googleAuth = require('google-auth-library');
var pg = require('pg');
const config = {
user: '<redacted>',
database: '<redacted>',
password: '<redacted>',
host: '<redacted>',
port: 5432,
max: 10,
idleTimeoutMillis: 5000,
};
const pool = new pg.Pool(config);
const spreadsheetId = '<this my internal sheet>'; // fulfillment kpis
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-nodejs-quickstart.json
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets'];
const TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
const TOKEN_PATH = TOKEN_DIR + 'olr-test.json';
// Load client secrets from a local file.
fs.readFile('secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Google Sheets API.
authorize(JSON.parse(content), begin); // <---- LOOK HERE...WHERE IT REALLY BEGINS...I THINK
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function (err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function (code) {
rl.close();
oauth2Client.getToken(code, function (err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* @param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
// Let's get the information out of xTuple now...
function begin(auth) {
// Promise function to return results from SQL query passed as an argument
function getResults(passedQuery) {
return new Promise((resolve, reject) => {
pool.connect((err, client, done) => {
var sql = client.query(passedQuery);
sql.on('row', (row, result) => {
result.addRow(row);
});
sql.on('end', (result) => {
var rightNow = timeStamp();
// console.log('Query finished at %s', rightNow);
resolve(result.rows);
});
done(err);
if (err) {
return console.error('error running query', err);
}
});
});
pool.on('error', (err, client) => {
console.error('idle client error', err.message, err.stack);
});
}
function convertArray(sqlObj) {
return new Promise((resolve, reject) => {
var result = [];
if (sqlObj.length > 0) {
var order = Object.keys(sqlObj[0]);
var result = sqlObj.map((row) => {
return order.map((col) => {
return row[col];
});
});
}
result[0].push(timeStamp());
resolve(result);
});
}
function appendSheet (value) {
return new Promise((resolve, reject) => {
var sheets = google.sheets('v4');
var options = {
auth: auth,
spreadsheetId: spreadsheetId,
range: "Sales ABPH!A1:B",
valueInputOption: "USER_ENTERED",
resource: {
range: "Sales ABPH!A1:B",
majorDimension: "ROWS",
values: value,
}
}
// console.log(options);
sheets.spreadsheets.values.append(options, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
});
});
}
function fixFormats(id) {
return new Promise((resolve, reject) => {
var sheets = google.sheets('v4');
var options = {
auth: auth,
spreadsheetId: spreadsheetId,
resource: {
requests: [{
repeatCell: {
fields: "userEnteredFormat.numberFormat",
range: {
sheetId: id,
startColumnIndex: 0, // inclusive
endColumnIndex: 1, // exclusive...meaning this counts UP TO column 4 but NOT 5
},
cell: {
userEnteredFormat: {
numberFormat: {
type: "CURRENCY",
pattern: "\"$\"#,##0.00",
}
}
}
}
}],
}
}
sheets.spreadsheets.batchUpdate(options, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
});
});
}
function timeStamp() {
var now = new Date();
var date = [now.getMonth() + 1, now.getDate()];
var time = [now.getHours(),now.getMinutes(),now.getSeconds()];
var suffix = (time[0] < 12) ? "AM" : "PM";
time[0] = (time[0] < 12) ? time[0] : time[0] - 12;
time[0] = time[0] || 12;
for (var i = 1; i < 3; i++) {
if (time[i] < 10) {
time[i] = "0" + time[i];
}
}
return date.join("/") + " " + time.join(":") + " " + suffix;
}
function insertRow() {
return new Promise((resolve, reject) => {
var sheets = google.sheets('v4');
var options = {
auth: auth,
spreadsheetId: spreadsheetId,
resource: {
requests: [{
insertRange: {
range: {
sheetId: 1769404692,
startRowIndex: 1,
endRowIndex: 2,
startColumnIndex: 1,
endColumnIndex: 4
},
shiftDimension: "ROWS",
}
}],
}
}
sheets.spreadsheets.batchUpdate(options, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
});
});
}
function update() {
getResults(`
select formatMoney(sum(qry.total)) as \"Booked\"
FROM cohead c
LEFT OUTER JOIN
(SELECT coitem_cohead_id, SUM(coitem_qtyord*coitem_price) as total
FROM coitem
WHERE coitem_status NOT IN (\'X\')
GROUP BY coitem_cohead_id) as qry
ON (c.cohead_id=qry.coitem_cohead_id)
WHERE (extract(DAY FROM c.cohead_orderdate) = extract(DAY from current_date) AND extract(MONTH from c.cohead_orderdate) = extract(MONTH from current_date) AND extract(YEAR from c.cohead_orderdate) = extract(YEAR from current_date))
`)
.then((sqlObj) => {
insertRow();
return convertArray(sqlObj);
})
.then((results) => {
console.log(results);
return appendSheet(results);
})
.then((fixMe) => {
fixFormats('1769404692');
})
.catch((error) => {
console.log('Something went wrong...\n%s', error);
});
tick();
}
function tick(force) {
var d = new Date();
var min = d.getMinutes();
var sec = d.getSeconds();
var hr = d.getHours();
if (force || (min == '0' && sec == '0') && (hr >= 7 || hr <= 19))
update();
else
setTimeout(update, (60 * (60 - min) + (60 - sec)) * 1000);
}
tick(true);
}
“严格使用”;
var fs=需要('fs');
var readline=require('readline');
var google=require('googleapis');
var googleAuth=require('google-auth-library');
var pg=需要(“pg”);
常量配置={
用户:“”,
数据库:“”,
密码:“”,
主机:“”,
港口:5432,
最高:10,
idleTimeoutMillis:5000,
};
const pool=新的pg.pool(配置);
常量电子表格ID=“”;//履行KPI
//如果修改这些作用域,请删除以前保存的凭据
//位于~/.credentials/sheets.googleapis.com-nodejs-quickstart.json
常量作用域=['https://www.googleapis.com/auth/spreadsheets'];
const TOKEN_DIR=(process.env.HOME | | process.env.HOMEPATH||
process.env.USERPROFILE)+'/.credentials/';
const TOKEN_PATH=TOKEN_DIR+'olr test.json';
//从本地文件加载客户端机密。
fs.readFile('secret.json',函数processClientSecrets(err,content){
如果(错误){
log('加载客户端机密文件时出错:'+err);
返回;
}
//使用加载的凭据授权客户端,然后调用
//GoogleSheetsAPI。
授权(JSON.parse(content),begin);//你的tick函数有点复杂。问题可能出在tick函数中。我只想简单地说一下。只需在一个间隔计时器上运行更新,看看它是否有效,比如说一分钟。如果有效,那么问题可能出在你的计时和pi时钟上。如果你不能调试它,可能是代码在它首先抓取,并且勾号永远不会被调用。尝试在更新中捕获异常。或者删除勾号函数工作并调用更新的所有代码测试,然后在更新中只需在PI上闪烁屏幕。这将帮助您缩小问题所在的范围。谢谢,我将尝试一下。勾号函数是必要的,但也许我可以简化正如您所建议的。滴答函数之所以要在下午1:00、下午2:00、下午3:00等时间运行。如果我按原样使用setInterval,并且在下午12:13启动脚本,那么它直到下午1:13才运行,这对我来说是不起作用的。我建议您只是为了测试/查找出现此错误的原因。如果工作人员说,每隔30秒,你就会知道这是你的勾号函数中的代码。我相信我已经找到了导致这一点的原因。我注意到,当我在办公桌旁或在脚本运行时让计算机保持运行时,一切都很好。它发生故障或偏移的时间是在我的计算机进入睡眠状态时。超时会暂停,并在我把机器弄醒。