Asynchronous function definitions on MongoDB (Atlas) Stitch display warnings on the GUI editor. Including the example code provided on the reference for Triggers.
The code found here can be was copied over directly to the Stitch Function editor and produces warnings because of the async keyword.
Example code from the docs.
exports = async function (changeEvent) {
// Destructure out fields from the change stream event object
const { updateDescription, fullDocument } = changeEvent;
// Check if the shippingLocation field was updated
const updatedFields = Object.keys(updateDescription.updatedFields);
const isNewLocation = updatedFields.some(field =>
field.match(/shippingLocation/)
);
// If the location changed, text the customer the updated location.
if (isNewLocation) {
const { customerId, shippingLocation } = fullDocument;
const twilio = context.services.get("myTwilioService");
const mongodb = context.services.get("mongodb-atlas");
const customers = mongodb.db("store").collection("customers");
const { location } = shippingLocation.pop();
const customer = await customers.findOne({ _id: customer_id })
twilio.send({
to: customer.phoneNumber,
from: context.values.get("ourPhoneNumber"),
body: `Your order has moved! The new location is ${location}.`
});
}
};
I want to know if Stitch supports the async/await paradigm and if I should be concerned about the warnings shown.
After some testing I found that at this time the async/await keywords cause the linter to throw errors and warnings. This means that for async callbacks it is best to define them separately as it will improve the linting. IE. [].map(async () => {}) will prompt errors that can be worked around.
The runtime execution returns the results as expected from standard asynchronous operations.
Related
This question already has an answer here:
Why is my PDF not saving intermittently in my Node function?
(1 answer)
Closed last year.
As described in the firebase docs, it is required to
"resolve functions that perform asynchronous processing (also known as
"background functions") by returning a JavaScript promise."
(https://firebase.google.com/docs/functions/terminate-functions?hl=en).
otherwise it might happen, that
"the Cloud Functions instance running your function does not shut down
before your function successfully reaches its terminating condition or
state. (https://firebase.google.com/docs/functions/terminate-functions?hl=en)
In this case I am trying to adapt a demo-code for pdf-generation written by Volodymyr Golosay on https://medium.com/firebase-developers/how-to-generate-and-store-a-pdf-with-firebase-7faebb74ccbf.
The demo uses 'https.onRequest' as trigger and fulfillis the termination requirement with 'response.send(result)'. In the adaption I need to use a 'document.onCreate' trigger and therefor need to find a different termination.
In other functions I can fulfill this requirement by using async/await, but here I am struggling to get a stable function with good performance. The shown function logs after 675 ms "finished with status: 'ok' ", but around 2 minutes later it logs again that the pdf-file is saved now (see screenshot of the logger).
What should I do to terminate the function properly?
// adapting the demo code by Volodymyr Golosay published on https://medium.com/firebase-developers/how-to-generate-and-store-a-pdf-with-firebase-7faebb74ccbf
// library installed -> npm install pdfmake
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const Printer = require('pdfmake');
const fonts = require('pdfmake/build/vfs_fonts.js');
const fontDescriptors = {
Roboto: {
normal: Buffer.from(fonts.pdfMake.vfs['Roboto-Regular.ttf'], 'base64'),
bold: Buffer.from(fonts.pdfMake.vfs['Roboto-Medium.ttf'], 'base64'),
italics: Buffer.from(fonts.pdfMake.vfs['Roboto-Italic.ttf'], 'base64'),
bolditalics: Buffer.from(fonts.pdfMake.vfs['Roboto-Italic.ttf'], 'base64'),
}
};
exports.generateDemoPdf = functions
// trigger by 'document.onCreate', while demo uses 'https.onRequest'
.firestore
.document('collection/{docId}')
.onCreate(async (snap, context) => {
const printer = new Printer(fontDescriptors);
const chunks = [];
// define the content of the pdf-file
const docDefinition = {
content: [{
text: 'PDF text is here.',
fontSize: 19 }
]
};
const pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.on('data', (chunk) => {
chunks.push(chunk);
});
pdfDoc.on('end', async () => {
const result = Buffer.concat(chunks);
// Upload generated file to the Cloud Storage
const docId = "123456789"
const bucket = admin.storage().bucket();
const fileRef = bucket.file(`${docId}.pdf`, {
metadata: {
contentType: 'application/pdf'
}
});
await fileRef.save(result);
console.log('result is saved');
// NEEDS PROPER TERMINATION HERE?? NEEDS TO RETURN A PROMISE?? FIREBASE DOCS: https://firebase.google.com/docs/functions/terminate-functions?hl=en
// the demo with 'https.onRequest' uses the following line to terminate the function properly:
// response.send(result);
});
pdfDoc.on('error', (err) => {
return functions.logger.log('An error occured!');
});
pdfDoc.end();
});
I think everything is fine in your code. It seems it takes 1m 34s to render the file and save it to storage.
Cloud function will be terminated automatically when all micro and macro tasks are done. Right after you last await.
To check how long does it takes and does it terminate right after saving, you can run the firebase emulator on your local machine.
You will see logs in the terminal and simultaneously watch on storage.
I suspect you did terminate properly - that's the nature of promises. Your function "terminated" with a 200 status, returning a PROMISE for the results of the PDF save. When the PDF save actually terminates later, the result is logged and the promise resolved. This behavior is WHY you return the promise.
https://www.selenium.dev/documentation/en/webdriver/locating_elements/ says:
Selenium 4 brings Relative Locators which are previously called as
Friendly Locators. This functionality was added to help you locate
elements that are nearby other elements. The Available Relative
Locators are:
above
below
toLeftOf
toRightOf
near
findElement method now accepts a new method withTagName() which
returns a RelativeLocator.
It also provides a JavaScript example for each of the locators:
let emailAddressField = driver.findElement(By.id('email'));
let passwordField = await driver.findElement(withTagName('input').below(emailAddressField));
When I try this myself:
const { Builder, By, Key, util } = require("selenium-webdriver")
const until = require("selenium-webdriver/lib/until")
const firefox = require("selenium-webdriver/firefox")
const firefoxOptions = new firefox.Options()
async function run() {
let driver = await new Builder().forBrowser("firefox").build()
await driver.get("https://www.google.com")
driver.wait(until.elementLocated(By.className("lnXdpd")), 4000).then(
async function(titleElement) {
driver.findElement(withTagName("div").below(titleElement)).then(function() {
console.log("TODO")
driver.quit()
})
},
function() {
console.warn("Failed to find element")
driver.quit()
}
)
}
run()
I get:
(node:21616) UnhandledPromiseRejectionWarning: ReferenceError: withTagName is not defined
My dependencies from package.json:
"dependencies": {
"selenium-webdriver": "^4.0.0-beta.4"
}
I tried finding some documentation about this on https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/, but there doesn't seem to be anything.
Searching around some more, I found that a test involving this API was fixed, so surely it must work.
What am I missing?
The issue was that withTagName was missing from the require line:
const { Builder, By, Key, util, withTagName } = require("selenium-webdriver")
I am using OrientDb with JavaScript and I have tried with startingWith, containing, endingWith, notContaining, notEndingWith, notStartingWith predicates unsuccessfully. Maybe is a wrong implementation from my side but I have not found documentation about how to use.
I've been looking for a way to filter with lambdas to get a sql like behavior but have not been successful. I tried to use the method described in this answer, but it is not working on JavaScript. When using the predicates the answer is an error.
I've tried that too:
What is the equivalent of the gremlin queries in gremlin javascript?
My current JavaScript code:
import * as gremlin from 'gremlin';
const traversal = gremlin.process.AnonymousTraversalSource.traversal;
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
const TextPredicated = gremlin.process.TextP;
const authenticator = new gremlin.driver.auth.PlainTextSaslAuthenticator('usr', 'pwd');
const remote = new DriverRemoteConnection(
'ws://localhost:8182/gremlin', {
authenticator,
traversalSource: 'g'
});
remote.addListener('socketError', (error) => { console.log(`socketError: ${error}`); });
(async () => {
try {
remote.open();
const g = await traversal().withRemote(remote);
const results = await g.V()
.where('username', TextPredicated.containing('john'))
.toList();
console.log(results);
remote.close();
} catch (error) {
console.log(error);
} finally {
remote.close();
}
})();
You don't say what your error is, but I think your Gremlin should use has() rather than where():
const results = await g.V()
.has('username', TextPredicated.containing('john'))
.toList();
Also note that TextP did not become available until TinkerPop 3.4.0 so you'd need to be sure that your graph (in your case, OrientDB) supports at least this version of TinkerPop.
I'm trying to add new fields to a new document after calculation, that I have to do when a new doc is created. But, the field isn't added.
I have deploy this code without any errors but when a new doc is added in this path, nothing happens..
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.test = functions.firestore.document('a/{a.id}/b/{b.id}/c/d')
.onCreate(async(snapshot, context) => {
const data = snapshot.data();
const userRef = db.doc(`a/${a.id}/b/${b.id}/c/d`);
var result = 1+2; //just for lighter code example
return userRef.update({
result: result
});
})
Your wildcards are invalid. You can't have a dot in the wildcard name. I'm kind of surprised that the Firebase CLI allowed you to deploy this function. Also, you're not using the wildcards correctly, even if those wildcards were valid.
There is an easier way to get a reference to the document that was just created. You can use snapshot.ref.
exports.test = functions.firestore.document('a/{a}/b/{b}/c/d')
.onCreate(async(snapshot, context) => {
var result = 1+2; //just for lighter code example
return snapshot.ref.update({
result: result
});
})
If you do want to use the wildcard values, you should use context.params instead, as described in the documentation.
I have an object repository file where I store all the locators. However to improve maintainability and readability, I am now grouping the locators using const. For example:
const delivery = {
DELIVERY_HEADING: "xpath=//div[OOtext()='Delivery']",
DELIVERY_COUNT: '.bit-deliverylistrow'
};
const operations = {
SAVE_AUD: '.bit-save-btn',
SAVE_AUDNAME: "xpath=//*[text()='Audience name']/../input"
};
module.exports = { delivery, operations }
In the tests, I am using importing and using them as:
const or = require('../TestData/OR');
await page.focus(or.delivery.DELIVERY_HEADING);
await page.type(or.operations.SAVE_AUDNAME,'hello');
Is there a way I don't have to refer to the const and directly call the object locators in the test as it is difficult to identify which const has which locator ?
I would like to do await page.focus(or.DELIVERY_HEADING)
Any pointers will be helpful.
You can use the spread ... to create a single object.
module.exports = { ...delivery, ...operations }
Now you can do,
await page.focus(or.DELIVERY_HEADING)