I'm trying to schedule several cron jobs to generate serial numbers for different entities within my web app. However I am running into this problem, when I'm looping each table, it says it has something to do with date.js. I'm not doing anything with a date object ? Not at this stage anyway. A couple of guesses is that the cron object is doing a date thing in its code and is referencing date.js. I'm using date.js to get access to things like ISO date.
for (t in config.generatorTables) {
console.log("t = " + config.generatorTables[t] + "\n\n");
var ts3 = azure.createTableService();
var jobSerialNumbers = new cronJob({
//cronTime: '*/' + rndNumber + ' * * * * *',
cronTime: '*/1 * * * * *',
onTick: function () {
//console.log(new Date() + " calling topUpSerialNumbers \n\n");
manageSerialNumbers.topUpSerialNumbers(config.generatorTables[t], function () { });
},
start: false,
timeZone: "America/Los_Angeles"
});
ts3.createTableIfNotExists(config.generatorTables[t], function (error) {
if (error === null) {
var query = azure.TableQuery
.select()
.from(config.generatorTables[t])
.where('PartitionKey eq ?', '0')
ts3.queryEntities(query, function (error, serialNumberEntities) {
if (error === null && serialNumberEntities.length == 0) {
manageSerialNumbers.generateNewNumbers(config.maxNumber, config.serialNumberSize, config.generatorTables[t], function () {
jobSerialNumbers.start();
});
}
else jobSerialNumbers.start();
});
}
});
}
And this is the error message I'm getting when I examine the server.js.logs\0.txt file:
C:\node\w\WebRole1\public\javascripts\date.js:56
onsole.log('isDST'); return this.toString().match(/(E|C|M|P)(S|D)T/)[2] == "D"
^
TypeError: Cannot read property '2' of null
at Date.isDST (C:\node\w\WebRole1\public\javascripts\date.js:56:110)
at Date.getTimezone (C:\node\w\WebRole1\public\javascripts\date.js:56:228)
at Object._getNextDateFrom (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:88:30)
at Object.sendAt (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:51:17)
at Object.getTimeout (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:58:30)
at Object.start (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:279:33)
at C:\node\w\WebRole1\server.js:169:46
at Object.generateNewNumbers (C:\node\w\WebRole1\utils\manageSerialNumbers.js:106:5)
at C:\node\w\WebRole1\server.js:168:45
at C:\node\w\WebRole1\node_modules\azure\lib\services\table\tableservice.js:485:7
I am using this line in my database.js file:
require('../public/javascripts/date');
is that correct that I only have to do this once, because date.js is global? I.e. it has a bunch of prototypes (extensions) for the inbuilt date object.
Within manageSerialNumbers.js I am just doing a callback, their is no code executing as I've commented it all out, but still receiving this error.
Any help or advice would be appreciated.
Ok I've commented out the date.js module and now I'm getting this error:
You specified a Timezone but have not included the time module. Timezone functionality is disabled. Please install the time module to use Timezones in your application.
When I examine the cron.js module it has this statement at the top:
var CronDate = Date;
try {
CronDate = require("time").Date;
} catch(e) {
//no time module...leave CronDate alone. :)
}
So this would conclude then that it does have something to do with the date.js module ?
Anyone see whats wrong.
cheers
I was using date.js for a while, and then realized that the Date object in Node.js/V8 already had ISO support, input and output, and Date.js only added a very specific edge case. What exactly do you need date.js for?
If you do need date.js...
is that correct that I only have to do this once, because date.js is global?
That's true as long as the code is running in the same process. I'm not familiar Node.js on Azure, or the library providing the cronJob method you're using, but perhaps it spawns a new process, which has its own V8 instance, and then you lose the Date object changes? (So require it again in that code.)
Related
I'm trying to create a small plugin to make my day-to-day job easier. I have faced a very strange situation within the popup.js script. The promise function randomly refuses to get executed. I have spent some hours trying to debug or at least understand where the issue could be but without any results.
Here is the skeleton of the code:
document.addEventListener('DOMContentLoaded', function () {
// some initialization
document.getElementById("signinbutton").addEventListener("click", function(event) {
try {
// some more initialization
var user_email = '';
var advertiserId = '';
var checkibm = '';
user_email = $('#emailfield').val().trim();
advertiserId = $('#advertiseridfield').val().trim();
checkibm = $('#checkibm').is(':checked');
if (advertiserId && checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (advertiserId && !checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (user_email && validateEmail(user_email))
{
_act = 'getTokenIdByEmail',
_data = user_email
}
else
{
throw new Error("Valid input has not been provided");
}
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
.then(responseHandler)
.then(responseReplaceTokenHandler)
.then(show_ok('Done'))
.catch(failureCallback);
}
catch (error){
//doing some error catching here
});
});
The code above works perfectly. However, as soon as I fill in the real values in sendMessagePromise e.g
//_act and _data show the proper values when inspected
sendMessagePromise({
act : _act,
data: _data//encodeURIComponent(user_email)
})
the flow skips execution of sendMessagePromise and any other chained function, except the last one ".then(show_ok('Done'))", i.e the only result is the "Done" message on the screen.
I made sure the values are correct. I'm able to debug step-by-step and see the values being properly supplied. I have also put a bunch of console messages inside the chain promise functions to see where the execution gets stuck, but it seems like it doesn't even start executing sendMessagePromise.
As soon as I replace expression back to hardcoded values i.e
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
it starts working again. I'm really stuck and not sure how to debug or which steps to take further.
Please assist
I have built a script that looks at fields within a saved search to process, when the script processes each line of the saved search . The script has to process a lot of lines of data and I'm running into issue where I get an SSS Usage Limit exceeded message just due to the nature of the amount of information that I'm processing. Therefore I'm wondering if on each run of the script if I can limit the amount of orders processed and then consecutively run the script until there aren't any more records that need to be processed
Previously I have just restricted the number of records that the script processes at a time and then just manually trigger the script until there aren't anymore lines left to process. I see that you can trigger the script to run every 15 minutes or so but would like it to run each day and then run in a 15 minute cadence after that until the saved search has been exhausted. Then the script would be triggered to run again the following day etc for every 15 min until all records are processed. From research don't know if this type of scheduling is possible.
code itself is working the scheduling of it is what I need guidance on
The other alternative (and one that I've used successfully) is to exit the scheduled script whent the usage reaches a certain point, but before you exit, trigger the scheduled script again. I've used this successfully to process thousands of records (such as mass deletions).
/**
* #NApiVersion 2.x
* #NScriptType ScheduledScript
* #NModuleScope SameAccount
*/
define(['N/record', 'N/runtime', 'N/search', 'N/task'],
/**
* #param {record} record
* #param {search} search
*/
function(record, runtime, search, task) {
const governanceCap = 9950;
function getAllResults(s) {
var results = s.run();
var searchResults = [];
var searchid = 0;
do {
var resultslice = results.getRange({start:searchid,end:searchid+1000});
resultslice.forEach(function(slice) {
searchResults.push(slice);
searchid++;
}
);
} while (resultslice.length >=1000);
return searchResults;
}
/**
* Definition of the Scheduled script trigger point.
*
* #param {Object} scriptContext
* #param {string} scriptContext.type - The context in which the script is executed. It is one of the values from the scriptContext.InvocationType enum.
* #Since 2015.2
*/
function execute(scriptContext) {
function rescheduleCurrentScript() {
var scheduledScriptTask = task.create({
taskType: task.TaskType.SCHEDULED_SCRIPT
});
scheduledScriptTask.scriptId = runtime.getCurrentScript().id;
scheduledScriptTask.deploymentId = runtime.getCurrentScript().deploymentId;
return scheduledScriptTask.submit();
}
try {
var script = runtime.getCurrentScript();
// GET YOUR SEARCH HERE
var mySearch = getAllResults(
search.create({
type: "transaction",
filters:
[
["mainline","is","T"],
],
columns:
[
"name",
"tranid",
"type",
search.createColumn({
name:"datecreated",
sort: search.Sort.DESC
}),
]
})
);
var recCount = mySearch.length;
for (each in mySearch) {
try {
record.delete({
type: transSearch[each].getValue({name:'type'}),
id: transSearch[each].id
});
} catch (err) {log.error(err.name,err.message) }
var govPointsUsed = 10000-script.getRemainingUsage();
script.percentComplete = (govPointsUsed/governanceCap*100).toFixed(1);
if (govPointsUsed >= governanceCap) {
var taskId = rescheduleCurrentScript();
log.audit('Rescheduling status: ','Task ID:' + taskId);
return;
}
}
} catch (err) { log.error(err.name,err.message + '; Stack: '+err.stack ) };
}
return {
execute: execute
};
});
Worked like a charm!!
I would encourage you to use a Map/Reduce script. That is the correct script type to use when dealing with a lot of data and can handle governance issues much better.
I had this problem some time ago. The map/reduce script can be the solution if you run 2.0 scripts. In my case, I had 'legacy' scripts in versions 1.X and 2.X. And all of them throw from time to time 'SSS_TIME_LIMIT_EXCEEDED'.
My solution :)
I created a script, kind of 'listener'. I removed link to the script because the rep. is not active anymore
// *add the script listener
// [it can be used for both script versions 1.X and 2.X]
/** you have to calculate the 'process usage' by 1 loop cycle.
use script.getRemainingUsage() */
var recallValue = 200;
var stopValue = 200;
var recallIsRequired = true;// use false to stop the script without recall
var script = setScriptListener(recallValue, stopValue, recallIsRequired);
for (var data in data_contaniner){
if(script.canContinue()){
//run you processing
// !important : mark the data as 'processed'.
//otherwise you will have a lot of duplicates after script recall
}else{
//stop the loop
break;
}
}
I'm trying to build a test script using node.js. I am utilising assert and using the mocha testing framework for this. A feature of this is to be testing that registering a new user always returns 200. To do this, I've declared a timestamp using the following method:
var currentDate = new Date();
var timestamp = currentDate.getTime();
var testInvitee = {
"username": "name.lastname+11231232" + timestamp + "#company.com"
};
The idea is whenever I run the test the string should be different as the timestamp will change. When running mocha, however, I receive this response:
Testing registration
Register new user:
AssertionError [ERR_ASSERTION]: 403 === 400
+ expected - actual
-200
+400
at Context.it (test.js:596:28)
at <anonymous>
I've done a number of console.log() calls during the course of the script which revealed that the timestamp is undefined. See response body below:
Testing as System User.
undefined
Testing candidates
undefined
√ Get candidates (145ms)
//more code
Testing registration
undefined
13) Register new user
I'm not sure as to why the timestamp is undefined in this instance. I'm expecting it to be milliseconds since Jan 1, 1970 as it normally is. Is there anything I've missed out or done incorrectly? Perhaps there is a library I should be using? If it's not the timestamp causing the problem, I have to assume the problem is deeper in the API but I am certain this is not the case.
EDIT: Here is the code block from the describe it blocks in case I've caused a problem in here also:
describe('Testing registration', function () {
before(async () => {
await backend.authenticate();
});
it('Register new user', async () => {
const output = await backend.registerUser()
console.log("", backend.timestamp);
switch (userLevel) {
case "CLIENT_ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "GROUP_ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "HR":
assert.strictEqual(200, output.statusCode);
break;
case "USER":
assert.strictEqual(200, output.statusCode);
break;
default:
console.log("No case match");
break;
}
});
})
The problem, most likely is in the scope.
Your code for declaring timestamp is correct. But the fact that on the tests the value is undefined tells us that the test scope does not have access to the scope where you defined the timestamp.
The easiest check for that would be too add the timestamp declaration right before it is used in the test.
Or just inline it:
var testInvitee = {
username: "name112233" + new Date().getTime() + "#company.com"
}
Other then that it is hard to tell without the full code. Plus why are you checking backend.timestamp with the console.log in the test?
Suppose I have this code running on 3 different servers and every server is using a single database.
setInterval(function(){
if(userArray) {
var report = mongoose.connection.db.collection('report');
report.insert({datenow:new Date(),userlist:userArray},function(err,doc) {
if(err) throw err;
});
}
},600000);
So, this piece of code is running every 10 minutes on every server but I want only one of them to insert the data into the database. Since the data is same it is getting inserted 3 times.
How do I check if the data is already inserted into the database by any one of the servers.
I tried making an incrementing count variable and insert it into the database and use it as a unique ID to check if it exists in the database. If it exists then I won't insert the data. But what if I have to restart the server for some reason, then the count will be reset to its initial value and this doesn't seem a viable solution.
So, how do I approach this problem? I am guessing I have to compare time somehow?
IMO, you should use a Cron expression instead of interval and use the execution time as primary key of your report when you perform the insertion in the database.
Explanation
Cron expression can garantee that the execution of your script will occur at an accurate time. If you use this Cron expression : 00 */10 * * * * (every 10 minutes), your script will execute at exactly 11:00:00, 11:10:00, 11:20:00, so on.. for every server you have.
So you can use this execution time as key for your reports and it will prevent multiple insertion of the same report.
Libs
You can use this lib to use Cron with Node.js : node-cron
Example
var CronJob = require('cron').CronJob;
new CronJob('* * * * * *', function() {
console.log('You will see this message every second');
}, null, true, 'America/Los_Angeles');
I hope this will help you.
So I had to end up comparing timestamps and checking it anything is inserted in the last 10 minutes. This is the solution I came up with.
setInterval(function(){
var currDate = new Date().getTime();
if(keyPairNameArray) {
var overallreport = mongoose.connection.db.collection('overallreport');
overallreport.find({}).sort({_id:-1}).limit(1).toArray(function(err, res){
if(res.length > 0){
var dbDate = new Date(res[0].datenow).getTime();
var diffDate = currDate - dbDate;
if(diffDate < 600000){
} else {
overallreport.insert({datenow:new Date(),userlist:keyPairNameArray},function(err,doc) {
if(err) throw err;
});
}
} else {
overallreport.insert({datenow:new Date(),userlist:keyPairNameArray},function(err,doc) {
if(err) throw err;
});
}
});
}
},610000);
I have a node.js script that does some database queries for me and works fine. The script is starting to get a bit longer so I thought I might start to break it up and thought moving the database connection code out to another file made sense.
Below is the code that I have moved into another file and then included with a require statement.
The issue I'm having is with the 'exports' commands at the bottom of the script. It appears the function 'dbHandleDisconnectUsers()' exports fine however the variable 'dbConnectionUsers' doesn't.
The script errors refer to methods of the object'dbConnectionUsers' (I hope thats the correct terminalogy) missing and gives me the impression I'm not really passing a complete object. Note: I would include the exact errors but I'm not in front of the machine.
var mysql = require('/usr/lib/node_modules/mysql');
// Users Database Configuration
var dbConnectionUsers;
var dbConfigurationUsers = ({
host : 'xxxxx',
user : 'xxxxx',
password : 'xxxxx',
database : 'xxxxxx',
timezone : 'Asia/Singapore'
});
// Users Database Connection & Re-Connection
function dbHandleDisconnectUsers() {
dbConnectionUsers = mysql.createConnection(dbConfigurationUsers);
dbConnectionUsers.connect(function(err) {
if(err) {
console.log('Users Error Connecting to Database:', err);
}else{
dbConnectionUsers.query("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;");
dbConnectionUsers.query("SET SESSION sql_mode = 'ANSI';");
dbConnectionUsers.query("SET NAMES UTF8;");
dbConnectionUsers.query("SET time_zone='Asia/Singapore';");
}
});
dbConnectionUsers.on('error', function(err) {
console.log('Users Database Protocol Connection Lost: ', err);
if(err.code === 'PROTOCOL_CONNECTION_LOST') {
dbHandleDisconnectUsers();
} else {
throw err;
}
});
}
dbHandleDisconnectUsers();
exports.dbHandleDisconnectUsers() = dbHandleDisconnectUsers();
exports.dbConnectionUsers = dbConnectionUsers;
In the core script I have this require statement:
var database = require('database-connect.js');
And I refer the function/variable as
database.dbHandleDisconnectUsers()
database.dbConnectionUsers
Ignoring the syntax error that everybody else has pointed out in exports.dbHandleDisconnectUsers() = dbHandleDisconnectUsers(), I will point out that dbConnectionUsers is uninitialized.
JavaScript is a pass-by-copy-of-reference language, therefore these lines:
var dbConnectionUsers;
exports.dbConnectionUsers = dbConnectionUsers;
are essentially identical to
exports.dbConnectionUsers = undefined;
Even though you set dbConnectionUsers later, you are not affecting exports.dbConnectionUsers because it holds a copy of the original dbConnectionUsers reference.
It's similar, in primitive data types, to:
var x = 5;
var y = x;
x = 1;
console.log(x); // 1
console.log(y); // 5
For details on how require and module.exports work, I will refer you to a recent answer I posted on the same topic:
Behavior of require in node.js
It's odd that your function is working but your other variable isn't exporting. This shouldn't be the case.
When you export functions you generally don't want to be exporting them as evaluated functions (ie. aFunction() ). The only time you might is if you want export whatever that function returns, or if you want to export an instance of a constructor function as part of your module.
The other thing, which is really odd, and is mentioned in a comment above is that you are trying to assign a value to exports.dbHandleDisconnectUsers(), which should be an undefined and throw an error.
So,in other words: Your code should not look like exports.whatever() = whatever().
Instead you should export both functions and other properties like this:
exports.dbHandleDisconnectUsers = dbHandleDisconnectUsers; // no evaluation ()
exports.dbConnectionUsers = dbConnectionUsers;
I don't know if this is the only thing wrong here, but this is definitely one thing that might be causing an execution error or two :)
Also, taking into consideration what Brandon has pointed out as well, you are initially exporting something undefined. But in your script, you are overwriting the reference anyway.
What you should do instead is make a new object reference, which is persistent and has a property in it that you can update. ie:
var dbConnection = {users: null};
exports.dbConnection = dbConnection;
Then when you run your function:
function dbHandleDisconnectUsers() {
dbConnection.users = mysql.createConnection(dbConfigurationUsers);
dbConnection.users.connect(function(err) {
if(err) {
console.log('Users Error Connecting to Database:', err);
}else{
dbConnection.users.query("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;");
dbConnection.users.query("SET SESSION sql_mode = 'ANSI';");
dbConnection.users.query("SET NAMES UTF8;");
dbConnection.users.query("SET time_zone='Asia/Singapore';");
}
});
dbConnection.users.on('error', function(err) {
console.log('Users Database Protocol Connection Lost: ', err);
if(err.code === 'PROTOCOL_CONNECTION_LOST') {
dbHandleDisconnectUsers();
} else {
throw err;
}
});
}
This way, the object reference of dbConnection is never overwritten.
You will then refer to your users db connection in your module as:
database.dbConnection.users
Your function should still work as you were intending on using it before with:
database.dbHandleDisconnectUsers();