I'm trying to follow this answer to connect to a mongodb atlas db from cloud functions.
I use this code from the answer above:
import { MongoClient } from 'mongodb'
const uri = 'mongodb://<USER>:<PASSWORD>#foo-shard-00-00-xxx.gcp.mongodb.net:27017,foo-shard-00-01-xxx.gcp.mongodb.net:27017,foo-shard-00-02-xxx.gcp.mongodb.net:27017/test?ssl=true&replicaSet=FOO-shard-0&authSource=admin&retryWrites=true'
let client
export default async () => {
if (client && client.isConnected()) {
console.log('DB CLIENT ALREADY CONNECTED')
} else try {
client = await MongoClient.connect(uri, { useNewUrlParser: true })
console.log('DB CLIENT RECONNECTED')
}
catch (e) {
throw e
}
return client
}
And then I have a function like this:
export const myFunction = functions.region('europe-west1').https.onRequest((request, response) => {
console.log(client.isConnected());
});
When I run firebase serve locally, I don't see 'DB CLIENT ALREADY CONNECTED' or 'DB CLIENT RECONNECTED' which means that anonymous function didn't get called. And when I try to access the client variable inside myFunction I get an error.
I'm learning Node at the moment so this might be a simple question. Thanks,
If you have some code to run in Cloud Functions, you need to invoke it. It's not possible to simply declare or export some function and expect it to run without calling it. If you want something to run at the global scope of your code, either don't wrap it in a function, or call the function at the global scope.
Related
I'm trying to prevent prisma from from shutting my app down even if it fails to connect to the database, so that my health-check endpoint can still be reached. The error I get is this:
throw new PrismaClientInitializationError(error2.message, this.config.clientVersion, error2.error_code);
^
Error: Can't reach database server at `postgres`:`5432`
Please make sure your database server is running at `postgres`:`5432`.
at startFn (/home/my_name/my_folder/my-service/node_modules/#prisma/client/runtime/index.js:27186:17)
at Proxy.onModuleInit (/home/my_name/my_folder/my-service/src/services/prisma.ts:12:5)
which makes sense, because my database is shut off. But this crashes my nest application.
The prisma docs say that the PrismaClientInitializationError is returned whenprisma.$connect runs, or if a query is run.
The obvious solution to me was to wrap this.$connect with a try catch to prevent it from crashing and burning. So here is my attempt in my PrismaService - the file that the error above is complaining about my-service/src/services/prisma:
import { INestApplication, Injectable, OnModuleInit } from '#nestjs/common';
import { PrismaClient, Prisma } from '#prisma/client';
#Injectable()
export class PrismaService
extends PrismaClient<Prisma.PrismaClientOptions, 'query' | 'error'>
implements OnModuleInit
{
constructor() {
try {
super();
} catch (e) {
console.log(e);
}
}
async onModuleInit() {
this.$on('error', (event) => {
console.log(event.target);
});
try {
await this.$connect();
} catch (e) {
console.log(e);
}
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
It's littered with console logs, and none of them log anything to the console. In fact, I found that even if I delete this.$connect if my database is up and running then prisma still connects to the database. If my database is not running I still get the same error message as above.
My question is, where do I need to put a try catch in order to prevent prisma from breaking my app?
And to satisfy my curiosity, why is the prisma client seemingly initializing itself even if I don't run this.$connect
This issue has seemingly resolved itself. and my error handling now works. I'm suspecting that because I was using docker compose with mounted volumes some sort of caching was getting in the way and not registering that I had put a try/catch there
I'm using the Flutter SDK to call a cloud function. I add a parameter someField but on the cloud side, it cannot be retrieved and is always undefined. This is how I call the cloud function
static Future<void> doSomething() async {
await Firebase.initializeApp();
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
functionName: 'myFunction',
);
dynamic resp = await callable.call(
<String, dynamic>{
'someField': 'Hurray!',
},
);
}
The cloud function is written as follows
exports.myFunction = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const myParameter = req.body.someField; // is always Undefined
// also tried
// req.query.someField
// req.params.someField
doSomething(myParamter)
})
});
You're mixing up callable functions on the client app with HTTPS functions on the backend. Please review the documentation to understand the difference between them. If you want to use the Firebase SDK on the client to invoke a Cloud Functions, you should declare that using onCall instead of onRequest. When you write a callable function with onCall, you will have access to the input arguments via the first parameter delivered to the callback.
exports.myFunction = functions.https.onCall((data, context) => {
// data.someField should be populated from your client request
});
I want to utilize mongoose's withTransaction helper particularly for its ability to automatically retry transient transaction errors. However, it seems that the withTransaction helper is incapable of returning data, which is a problem for me.
I have code that looks like:
import { startSession } from 'mongoose';
async addItem(itemData) {
const session = await startSession();
session.startTransaction();
try {
const item = await new Item({ itemData }).save({ session });
// a bunch of other async operations...
await session.commitTransaction();
session.endSession();
return item;
} catch (error) {
await session.abortTransaction();
session.endSession();
throw error;
}
}
How can I either (1) use the withTransaction helper but still have this function returning the item as it currently does, or (2) make this function automatically retry on transient transaction errors through some way other than using withTransaction.
This appears to be a known issue in the node driver. Some workarounds are provided in that ticket.
I wrote a simple helper that internally uses withTransaction to solve the problem and make transactions less verbose with mongoose.
After installing mongoose-trx you can simply do:
const transaction = require('mongoose-trx');
const [customer] = await transaction(session => Customer.create([{ name: 'Test' }], { session }));
// do whatever you need to do with the customer then return it
It supports transaction options as well, see the documentation on how to do it.
I am trying to send emails using js on firebase and am struggling to call back-end functions through firebase.
Here is the simple function I would like to call (inside index.js)
const functions = require('firebase-functions');
exports.test = functions.https.onCall((data, context) => {
return 1;
});
I would like to be able to call it through my script or external js like so:
function sendEmail()
{
var testFunction = firebase.functions().httpsCallable('test');
alert(testFunction());
}
^ This is inside the script tag of the index.html file
I've tried following https://firebase.google.com/docs/functions/callable
but have trouble understanding it
I've also tried seeing how this example of an email sender works and work with that but all the functions are triggered by the event of a user logging in or deleting their account: https://github.com/firebase/functions-samples/tree/master/quickstarts/email-users#functions-code
Follow the steps given in the link: Set up your local environment. Then add the following function.
function sendEmail() {
return new Promise((resolve,reject)=>{
firebase.functions().httpsCallable('test')().then(function(result) {
// Handle result of your cloud function.
resolve(data)
}).catch(function(err){
//Handle error
reject(err)
});
})
}
Now you can call this function anywhere. Your mistake was that you were calling sendEmail() as a synchronous function but it is an asynchronous function.
Hope it helps!
I want to use MongoDB connection object to different module. Problem is whenever my app.js run it should get instantiate then i can pass to other function of module.
Basically Mongo connection should be create only 1 time,
Currently i am using this code whenever we want to call MongoDb.How we can reuse MongoDb connection object outside of callback function.
var mongodb = require("mongodb");
mongodb.MongoClient.connect(url, function (err, db) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
console.log("Database connection ready");
});
//let say here i want to use
db.collection("cname").find({}) //but i am getting db as undefined.
The "false good idea" would be to use an other variable in the upper scope to store your db instance:
var mongodb = require("mongodb");
var dbInstance;
mongodb.MongoClient.connect(url, function (err, db) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
console.log("Database connection ready");
dbInstance = db;
});
// Here I don't know if dbInstance is define or not -> big problem!
Still, if this looks like a good idea, it's not. It will give you an error about dbInstance being undefined. mongodb.MongoClient.connect is async, so you'll need to wait for the callback before using "dbInstance".
It's better to use functions to which you'll pass the db instance as a argument:
var mongodb = require("mongodb");
var myModule = require("myModule")
var useDbInstance = function useDbInstance(dbInstance) {
//let say here i want to use
dbInstance.collection("cname").find({});
myModule(dbInstance)
.doSomething();
};
mongodb.MongoClient.connect(url, function (err, db) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
console.log("Database connection ready");
useDbInstance(db);
});
Then you could wrap you code in Promises to have a better control over the async flow and avoid the "callback hell".
I hope this helps :)