I'm having a problem with node modules that I cannot resolve. I have the following three files. I've included the basic methods of interest but have excluded the rest of the methods and the actual guts of the methods.
The problem that I'm struggling with is that when the publish_event method is called on the event_queue object from events.js node crashes with the following error:
FATAL TypeError: Object # has no method 'publish_event', stack:
TypeError: Object # has no method 'publish_event'
at Events.publish_event (/Users/mburbidg/stormcloud/ccapi/cloud_pipes/node_modules/f5/server/services/event/events.js:137:15)
I cannot figure this out, you can see that I can use methods of the EventQueue object from index.js, another module, in our system just fine. I've checked names other obvious things several times.
Any suggestions as to how to proceed?
File 1 - f5/server/notifications/sqs_event_queue.js
function EventQueue() {
this.queue_name = 'notification_queue';
this.queue_url = null;
this.sqs = null;
}
EventQueue.prototype.publish_event = function(event_data, registration_id, log, callback) {
...
}
EventQueue.prototype.start = function(callback) {
...
}
module.exports = new EventQueue();
File 2 - f5/server/index.js
var event_queue = require('f5/server/notifications/sqs_event_queue');
var start_notifications = function()
{
event_queue.start(on_start);
function on_start(error)
{
}
}
File 3 - f5/server/services/event/events.js
var event_queue = require('f5/server/notifications/sqs_event_queue');
function Events () {
}
Events.prototype.publish_event = function(event_data, registration_id, log, callback) {
event_queue.publish_event(event_data, registration_id, log, callback);
};
module.exports = new Events();
Related
I created a script in Google Sheets, which is working well but after a while I'm getting the following error:
Exception: Service invoked too many times for one day: urlfetch
I think I called the function like 200-300 times in the day, for what I checked it should be below the limit.
I read we can use cache to avoid this issue but not sure how to use it in my code.
function scrapercache(url) {
var result = [];
var description;
var options = {
'muteHttpExceptions': true,
'followRedirects': false,
};
var cache = CacheService.getScriptCache();
var properties = PropertiesService.getScriptProperties();
try {
let res = cache.get(url);
if (!res) {
// trim url to prevent (rare) errors
url.toString().trim();
var r = UrlFetchApp.fetch(url, options);
var c = r.getResponseCode();
// check for meta refresh if 200 ok
if (c == 200) {
var html = r.getContentText();
cache.put(url, "cached", 21600);
properties.setProperty(url, html);
var $ = Cheerio.load(html); // make sure this lib is added to your project!
// meta description
if ($('meta[name=description]').attr("content")) {
description = $('meta[name=description]').attr("content").trim();
}
}
result.push([description]);
}
}
catch (error) {
result.push(error.toString());
}
finally {
return result;
}
}
how can I use cache like this to enhance my script please?
var cache = CacheService.getScriptCache();
var result = cache.get(url);
if(!result) {
var response = UrlFetchApp.fetch(url);
result = response.getContentText();
cache.put(url, result, 21600);
Answer:
You can implement CacheService and PropertiesService together and only retrieve the URL again after a specified amount of time.
Code Change:
Be aware that additional calls to retrieving the cache and properties will slow your function down, especially if you are doing this a few hundred times.
As the values of the cache can be a maximum of 100 KB, we will use CacheService to keep track of which URLs are to be retrieved, but PropertiesService to store the data.
You can edit your try block as so:
var cache = CacheService.getScriptCache();
var properties = PropertiesService.getScriptProperties();
try {
let res = cache.get(url);
if (!res) {
// trim url to prevent (rare) errors
url.toString().trim();
var r = UrlFetchApp.fetch(url, options);
var c = r.getResponseCode();
// check for meta refresh if 200 ok
if (c == 200) {
var html = r.getContentText();
cache.put(url, "cached", 21600);
properties.setProperty(url, html);
var $ = Cheerio.load(html); // make sure this lib is added to your project!
// meta description
if ($('meta[name=description]').attr("content")) {
description = $('meta[name=description]').attr("content").trim();
}
}
result.push([description]);
}
}
catch (error) {
result.push(error.toString());
}
finally {
return result;
}
References:
Class CacheService | Apps Script | Google Developers
Class Cache | Apps Script | Google Developers
Class PropertiesService | Apps Script | Google Developers
Related Questions:
Service invoked too many times for one day: urlfetch
Back in Parse Server 3.0 update, there was an addition of request.context to pass data between BeforeSave and AfterSave as documented here:
https://docs.parseplatform.org/cloudcode/guide/#using-request-context
However, I'm having a bit of trouble understanding how and when Parse runs this code in the example.
const beforeSave = function beforeSave(request) {
const { object: role } = request;
// Get users that will be added to the users relation.
const usersOp = role.op('users');
if (usersOp && usersOp.relationsToAdd.length > 0) {
// add the users being added to the request context
request.context = { buyers: usersOp.relationsToAdd };
}
};
const afterSave = function afterSave(request) {
const { object: role, context } = request;
if (context && context.buyers) {
const purchasedItem = getItemFromRole(role);
const promises = context.buyers.map(emailBuyer.bind(null, purchasedItem));
item.increment('orderCount', context.buyers.length);
promises.push(item.save(null, { useMasterKey: true }));
Promise.all(promises).catch(request.log.error.bind(request.log));
}
};
in other examples, cloud code functions are run via Parse.Cloud.beforeSave or Parse.Cloud.afterSave. In this example above, the function beforeSave is assigned to a
const beforeSave.
Why was this done and is this supposed to be placed inside main.js top level or inside another function?
This particular code has been now running without issues for months, this morning, without any relevant change I can pinpoint in our setup or our code I started receiving
ERROR Error: Uncaught (in promise): Error: Network error: Cannot convert undefined or null to object Error: Network error: Cannot convert undefined or null to object
at new ApolloError (ApolloError.js:43)
at eval (QueryManager.js:324)
at eval (QueryManager.js:755)
at Array.forEach (<anonymous>)
at eval (QueryManager.js:754)
at Map.forEach (<anonymous>)
at QueryManager.broadcastQueries (QueryManager.js:749)
at eval (QueryManager.js:251)
at ZoneDelegate.invoke (zone.js:388)
at Object.onInvoke (core.js:4733)
at new ApolloError (ApolloError.js:43)
at eval (QueryManager.js:324)
at eval (QueryManager.js:755)
at Array.forEach (<anonymous>)
...
inline.bundle.js:26 (anonymous) # main.bundle.js:1
This happens because of an error at Object.keys(src).forEach:
var hasOwn = Object.prototype.hasOwnProperty;
export function merge(dest, src) {
Object.keys(src).forEach(function (key) {
var srcVal = src[key];
if (!hasOwn.call(dest, key)) {
dest[key] = srcVal;
}
else if (srcVal && typeof srcVal === 'object') {
merge(dest[key], srcVal);
}
});
}
The error is:
"Cannot convert undefined or null to object"
merge is called from here:
function executeSelectionSet(selectionSet, rootValue, execContext) {
var fragmentMap = execContext.fragmentMap, contextValue = execContext.contextValue, variables = execContext.variableValues;
var result = {};
selectionSet.selections.forEach(function (selection) {
if (!shouldInclude(selection, variables)) {
// Skip this entirely
return;
}
if (isField(selection)) {
var fieldResult = executeField(selection, rootValue, execContext);
var resultFieldKey = resultKeyNameFromField(selection);
if (fieldResult !== undefined) {
if (result[resultFieldKey] === undefined) {
result[resultFieldKey] = fieldResult;
}
else {
merge(result[resultFieldKey], fieldResult);
}
}
}
else {
var fragment = void 0;
if (isInlineFragment(selection)) {
fragment = selection;
}
else {
// This is a named fragment
fragment = fragmentMap[selection.name.value];
if (!fragment) {
throw new Error("No fragment named " + selection.name.value);
}
}
var typeCondition = fragment.typeCondition.name.value;
if (execContext.fragmentMatcher(rootValue, typeCondition, contextValue)) {
var fragmentResult = executeSelectionSet(fragment.selectionSet, rootValue, execContext);
merge(result, fragmentResult);
}
}
});
if (execContext.resultMapper) {
return execContext.resultMapper(result, rootValue);
}
return result;
}
After I identified the field that was being parsed and the fact the it was null valued in the backend I tried to change the value and then the error moved to the next null valued field for the same node. I tried also with other queries and we have the same result.
We are using django and graphene at the backend and apollo-client at the frontend.
I would be grateful for any insight here, I am still trying to understand what has changed between 23:00 yesterday (latest time I tested the code that is now bombing and it all worked) and 1am tonight (time of the automated deployment on our dev server).
I got a similar error last night and for me, I was able to track it down to a change in the graphql-anywhere package from version 4.1.8 to 4.1.9 (updated 2 days ago).
Here is the changelog: https://github.com/apollographql/apollo-client/blob/master/packages/graphql-anywhere/CHANGELOG.md
Adding "graphql-anywhere": "4.1.8", to my package.json file has solved the issue for my app.
When spying on a method, we can either callThrough (use original implementation) or callFake (use a custom implementation).
What I want is a behaviour similar to callThrough but inspect/modify its return value before returning it to the caller.
So I can do something like this:
spyOn(foo, "fetch").and.afterCall(function(result) {
expect(result).toBeDefined();
result.bar = "baz";
return result;
});
Right now the simplest way is doing something like this:
var original = foo.fetch;
foo.fetch = function() {
var result = original.apply(this, arguments);
expect(result).toBeDefined();
result.bar = "baz";
return result;
}
Which is somewhat annoying because now I have to manually restore the spy instead of having the framework automatically does it for me.
Does Jasmine have an after-advice spy?
Generally: no.
You could extend the SpyStrategy object with such a function though:
this.callThroughAndModify = function(resultModifier) {
var result;
plan = function() {
result = originalFn.apply(this, arguments);
return resultModifier(result);
};
return getSpy();
};
You've to clone the above SpyStrategy file and insert that method.
Usage:
var obj = {
fn: function(a) { return a * 2; }
};
spyOn(obj, "fn").and.callThroughAndModify(function(result) {
console.log("Original result: ", result);
return 1;
});
expect(obj.fn(2)).toBe(1);
Drawbacks:
You've to replace the whole SpyStrategy.js
You've to load that script before Jasmine initializes the original SpyStrategy at boot
I follow this guide to inherit a class, but i get crash with dalvik.system.NativeStart.main(native method) error
var MyDatePicker = android.widget.DatePicker.extend({
init: function() {
var isConstructor = arguments[arguments.length - 1];
if (isConstructor) {
// we are called from Java constructor
console.log('con')
} else {
// we are called from Java init method
console.log('init');
}
}
});
var foo = new MyDatePicker();
According Android documentation (http://developer.android.com/reference/android/widget/DatePicker.html) DatePicker constructor takes at least one parameter (context). Try passing it, for example
var foo = new MyDatePicker(context);