I have a Firebase DB with a { hello: 'world'} at its root. Whenever I try to read hello's value in Node, the callback isn't executed unless I modify the value from within the Node process.
Here's the once call:
let callback = (snapshot) => {
console.log('The value is ', snapshot.val());
};
db.ref('hello').once('value', callback);
At this point I'd expect the callback to run and print "The value is world" printed... but nothing happens. Now say I use on instead of once. Even if I modify the value from the Firebase web console or another Node process, the callback still isn't called! The strange thing is all of this code works as expected in a browser with the same library version (v3.0.2).
The only way I've managed to execute the callback is by modifying the value directly from the same Node process.
db.ref('hello').once('value', callback);
db.ref('test').set('moon');
// => 'The value is moon.'
I've created a repository with test scripts to help replicate an debug the issue.
It turns out this is a known issue affecting certain accounts, and the Firebase team is working on it!
Related
Let's say I have a node in a secondary realtime database called "test" with a value of "foobar".
I want to set up a function that prevents it from being deleted. More realistically this node would have several child nodes, where the function first checks if it can be deleted or not. However, here we never allow it to be deleted to keep the code as short as possible.
So I add a function that triggers onDelete and just rewrites the value.
In short:
Secondary database has: {"test":"foobar"}
onDelete function:
exports.testDelete = functions.database
.instance("secondary")
.ref("test")
.onDelete(async (snap, context) => {
await snap.ref.set(snap.val());
});
When running this with emulators, I would expect that when I delete the node, the node would just reappear in the secondary database, which is what happens when deployed to production. In the emulators, the node reappears, but in the main database instead of the secondary database. The only way I see to fix this is to replace snap.ref.set(snap.val()) with admin.app().database("https://{secondarydatabasedomain}.firebasedatabase.app").ref().child("test").set(snap.val()) which looks a little cumbersome just to get emulators to work.
Am I doing something wrong here?
I am using node 14, and firebase CLI version 9.23.0
To specify instance and path :
You have followed the syntax :
Instance named "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')
You have mentioned the instance name otherwise it will redirect to the default database so the syntax seems correct.
For triggering the event data follow the syntax as :
onDelete(handler: (snapshot: DataSnapshot, context: EventContext) => any): CloudFunction
For example you can refer to the Documentation :
// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = snapshot.val();
functions.logger.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return snapshot.ref.parent.child('uppercase').set(uppercase);
});
If all above syntax has been followed correctly then I will recommend you to report a bug with a minimal repro on the repo along with including the entire cloud function as mentioned by Frank in a similar scenario.
I have been trying to do some changes regarding the code below. At first I discovered that a function that returns a promise and in which a query is sent to db to be executed was being run twice instead of once. I have checked the query and the function itself just to make sure. Then I removed all code from inside io.of() except socket.on() functions which didn't seem to be involved in this matter. I have put a simple console.log() statement inside after removing the code I mentioned and it also produced the 'being executed twice' problem.
io.of('....').on('connection', socket => {
console.log("hello");
//...
//......
// below are socket.on('...')... and nothing more
})
Adding this to html and moving the code to socket.on('load') in io.of() fixed it for me.
$(document).ready(function () {
socket.emit('load');
});
I am developing Chatbot using Azure functions. I want to load the some of the conversations for Chatbot from a file. I am looking for a way to load these conversation data before the function app starts with some function callback. Is there a way load the conversation data only once when the function app is started?
This question is actually a duplicate of Azure Function run code on startup. But this question is asked for C# and I wanted a way to do the same thing in NodeJS
After like a week of messing around I got a working solution.
First some context:
The question at hand, running custom code # App Start for Node JS Azure Functions.
The issue is currently being discussed here and has been open for almost 5 years, and doesn't seem to be going anywhere.
As of now there is an Azure Functions "warmup" trigger feature, found here AZ Funcs Warm Up Trigger. However this trigger only runs on-scale. So the first, initial instance of your App won't run the "warmup" code.
Solution:
I created a start.js file and put the following code in there
const ErrorHandler = require('./Classes/ErrorHandler');
const Validator = require('./Classes/Validator');
const delay = require('delay');
let flag = false;
module.exports = async () =>
{
console.log('Initializing Globals')
global.ErrorHandler = ErrorHandler;
global.Validator = Validator;
//this is just to test if it will work with async funcs
const wait = await delay(5000)
//add additional logic...
//await db.connect(); etc // initialize a db connection
console.log('Done Waiting')
}
To run this code I just have to do
require('../start')();
in any of my functions. Just one function is fine. Since all of the function dependencies are loaded when you deploy your code, as long as this line is in one of the functions, start.js will run and initialize all of your global/singleton variables or whatever else you want it to do on func start. I made a literal function called "startWarmUp" and it is just a timer triggered function that runs once a day.
My use case is that almost every function relies on ErrorHandler and Validator class. And though generally making something a global variable is bad practice, in this case I didn't see any harm in making these 2 classes global so they're available in all of the functions.
Side Note: when developing locally you will have to include that function in your func start --functions <function requiring start.js> <other funcs> in order to have that startup code actually run.
Additionally there is a feature request for this functionality that can voted on open here: Azure Feedback
I have a similar use case that I am also stuck on.
Based on this resource I have found a good way to approach the structure of my code. It is simple enough: you just need to run your initialization code before you declare your module.exports.
https://github.com/rcarmo/azure-functions-bot/blob/master/bot/index.js
I also read this thread, but it does not look like there is a recommended solution.
https://github.com/Azure/azure-functions-host/issues/586
However, in my case I have an additional complication in that I need to use promises as I am waiting on external services to come back. These promises run within bot.initialise(). Initialise() only seems to run when the first call to the bot occurs. Which would be fine, but as it is running a promise, my code doesn't block - which means that when it calls 'listener(req, context.res)' it doesn't yet exist.
The next thing I will try is to restructure my code so that bot.initialise returns a promise, but the code would be much simpler if there was a initialisation webhook that guaranteed that the code within it was executed at startup before everything else.
Has anyone found a good workaround?
My code looks something like this:
var listener = null;
if (process.env.FUNCTIONS_EXTENSION_VERSION) {
// If we are inside Azure Functions, export the standard handler.
listener = bot.initialise(true);
module.exports = function (context, req) {
context.log("Passing body", req.body);
listener(req, context.res);
}
} else {
// Local server for testing
listener = bot.initialise(false);
}
You can use global variable to load data before function execution.
var data = [1, 2, 3];
module.exports = function (context, req) {
context.log(data[0]);
context.done();
};
data variable initialized only once and will be used within function calls.
I am very confused by what I am getting from my code. I have the following which should log out data.points then set this.state.points to data.points and then log out this.state.points, however when it logs them out they are not equal. This is the exact code I am using, so I am sure it is what was outputted. I am probably overlooking something, but I have spent the past hour reading over and logging out this code, and I still cannot figure it out. Here is the code that I run:
console.log(data.points);
if (!this.state.hasPressed) {
this.setState({points: data.points})
console.log('in not hasPressed if');
}
console.log(this.state.points);
However in the chrome remote debugger I get this:
["114556548393525038426"]
in not hasPressed if
[]
setState is an asynchronous call. you have to use function callback to wait for setState complete.
console.log(data.points);
if (!this.state.hasPressed) {
this.setState({points: data.points}, () => {
console.log(this.state.points);
});
console.log('in not hasPressed if');
}
refer to react-native setState() API:
setState(updater, [callback])
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
When I try to run my nodejs based Azure Function, I'm experiencing an issue where it doesn't generate any feedback and in some cases, I end up getting the following message:
2017-04-05T00:18:15.969 Exception while executing function: Functions.AddAuthor. Microsoft.Azure.WebJobs.Script: Thread was being aborted.
All my function code is publicly available, you can see it here. The library it's using works locally. I'm at a bit of a loss as to why it doesn't want to work in Azure Functions.
I originally posted this over at the Azure Functions github repo, but it was suggested that I maybe ask here.
Additionally, it seems like even a simple context.log won't even work.
One thing I notice - context does not exist in this scope: https://github.com/atrauzzi/anecdote-azure/blob/master/functions/index.js#L13
If I set up a similar function I see:
2017-04-12T17:06:55.433 Exception while executing function:
Functions.ManualJS. mscorlib: ReferenceError: context is not defined
at Object. (D:\home\site\wwwroot\ManualJS\test.js:1:63)
Also, 'anecdoteService' is not defined in this scope.
anecdote.service
.addAuthor(author)
.then(function () { anecdoteService.close()})
.then(function () { context.log("End of line")})
Does the function work with the azure-functions-cli?
Looking at the gist you provided, did you provide a function?
// index.js
module.exports = function(context) {
context.log('hello');
//there needs to be a context.done or your function will not finish
}
or was it simply
// index.js
context.log('hello'); // there's no context object, no function, etc