I am new to the 'nodejs' world.So wanting to explore the various technologies,frameworks involved i am building a simple user posts system(users posting something everybody else seeing the posts) backed by redis.I am using express framework which is recommended by most tutorials.But i have some difficulty in gettting data from the redis server i need to do 3 queries from the redis server to display the posts.In which case have to use neested callback after each redis call.So i wanted to use streamline.js to simplify the callbacks.But i am unable to get it to work even after i used npm install streamline -g and require('streamline').register(); before calling
var keys=['comments','timestamp','id'];
var posts=[];
for(var key in keys){
var post=client.sort("posts",'by','nosort',"get","POST:*->"+keys[key],_);
posts.push(post);
}
i get the error ReferenceError: _ is not defined.
Please point me in the right direction or point to any resources i might have missed.
The require('streamline').register() call should be in the file that starts your application (with a .js extension). The streamline code should be in another file with a ._js extension, which is required by the main script.
Streamline only allows you to have async calls (calls with _ argument) at the top level in a main script. Here, your streamline code is in a module required by the main script. So you need to put it inside a function. Something like:
exports.myFunction = function(_) {
var keys=['comments','timestamp','id'];
var posts=[];
for(var key in keys){
var post=client.sort("posts",'by','nosort',"get","POST:*->"+keys[key],_);
posts.push(post);
}
}
This is because require is synchronous. So you cannot put asynchronous code at the top level of a script which is required by another script.
Related
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.
Hi I am structuring my Node.js project based on this, like so:
Root
product name
index.js: (contains requires for the product and the main export)
productName.js: contains application logic
test
test1.js
test2.js
...
Now I have two questions
What should logically go in index.js? At the moment I have this (would this be a good way to do things and what else might I include in index.js?):
// index.js
var myServer = require('./myServer.js'); // "product name" = "myServer"
module.exports = {
run: myServer.listen
}
Does it matter what I call the object key in module.exports (currently "run")? Why does the server always run when I execute index.js with $ node index.js how does it automatically know to run myServer.listen?
P.S.: I am aware of web structure auto-generation tools, I just wish to understand the logical reason for this suggested structure (the idea of not having any logic in index.js)
As you mentioned this is a Express service, if it is only handling backend of some application or more specifically this is only backend application, I would suggest you change name of your index.js to server.js(Thus explicitly stating that it'll process all service requests).
But if not then even index.js is fine.
Now for
1
What you've put is absolutely fine, apart from this you could require all modules, routes(or controllers whatever you name them) in a way that it serves as entry point to your application. Try not to put any logic in here.
2
Actually the server runs because it executes the script in the file called index.js, the script says myServer.listen, now if you had written console.log("Hello World") and used $ node index.js it would've printed Hello World instead.
Node just expects and executes script that is there in index.js, in your case it is to start the server.
About the logic that why not put anything else in index.js, for me the reasoning I consider good enough is it provides abstraction as it is the entry point I don't want index.js to worry about things like what to do with this data and all. I believe it should provide a base to setup server. Thus following single responsibility to some extent. Also I won't have to touch it ever in projects lifetime unless some major change occurs e.g. I decide to shift from express to something else.
EDIT
Why have a key called run
You seem to have answered it yourself(in comments), you are giving or more proper description would be you're attaching an object to module.exports as it is a object similar to JSON it was supposed to have a key(which could be anything not necessarily run it could've been hii). Now if you don't want to pass a key and export only one thing that is server.listen then you could write same as module.exports = myServer.listen; instead of
module.exports = {
hii: myServer.listen
}
Note that you could export more modules using the way you did. For more details about module.exports refer this or better google about it as this link might expire anytime and does not seem an ideal thing to put on SO.
I'm building a project with AdonisJS, and I want to build it as a modular, two-part application: The AdonisJS server runs a control panel, and a custom script outside that server runs an IRC bot. I've been trying to load Lucid into the second script so that I can interface with my database, but it only ever returns an empty object, {}. Some things to note:
I've made sure my database is populated.
I've tested code in my controllers that works and fetches results as expected.
The secondary script boots up all the same parts of Adonis as server.js, sans the actual HTTP server.
I have tried attaching this script to an HTTP server but it made no difference.
I have also tried creating raw QueryBuilder objects with the same results.
Here's the least amount of code I can put together as an example:
#!/usr/bin/node
'use strict'
const fs = require('fs')
const bootstrap = require('./bootstrap/bot')
bootstrap(() =>
{
const AppConfig = use('AppConfig')
const Settings = use('App/Model/Settings')
const get_settings = function * () {
yield Settings.all()
}
console.log(get_settings())
})
console.log() prints {}, even though the same code called within a controller prints all entries from the settings table. bootstrap/bot.js is almost an exact replica of bootstrap/http.js. The only difference is that it doesn't start an HTTP server.
I've scoured the source code looking for things that might happen between starting the server and running controller code to see if there's something critical I'm missing, but I'm lost.
Does anyone know how I can use my Lucid models outside the confines of AdonisJS controllers?
It's because your function is a generator and you can only call a generator with the yield keyword.
So your console.log() should looks like console.log(yield get_settings()).
You may use the package co to create the root generator function.
bootstrap(co(function * () {
// ...
}))
I have a nodejs application and I want to write data into hadoop HDFS file system. I have seen two main nodejs libraries that can do it: node-hdfs and node-webhdfs. Someone have tried it? Any hints? Which one should I use in production?
I am inclined to use node-webhdfs since it uses WebHDFS REST API. node-hdfs seem to be a c++ binding.
Any help will be greatly appreciated.
You may want to check out webhdfs library. It provides nice and straightforward (similar to fs module API) interface for WebHDFS REST API calls.
Writing to the remote file:
var WebHDFS = require('webhdfs');
var hdfs = WebHDFS.createClient();
var localFileStream = fs.createReadStream('/path/to/local/file');
var remoteFileStream = hdfs.createWriteStream('/path/to/remote/file');
localFileStream.pipe(remoteFileStream);
remoteFileStream.on('error', function onError (err) {
// Do something with the error
});
remoteFileStream.on('finish', function onFinish () {
// Upload is done
});
Reading from the remote file:
var WebHDFS = require('webhdfs');
var hdfs = WebHDFS.createClient();
var remoteFileStream = hdfs.createReadStream('/path/to/remote/file');
remoteFileStream.on('error', function onError (err) {
// Do something with the error
});
remoteFileStream.on('data', function onChunk (chunk) {
// Do something with the data chunk
});
remoteFileStream.on('finish', function onFinish () {
// Upload is done
});
Not good news!!!
Do not use node-hdfs. Although it seems promising, it is now two years obsolete. I've tried to compile it but it does not match the symbols of current libhdfs. If you want to use something like that you'll have to make your own nodejs binding.
You can use node-webhdfs but IMHO there's not much advantage on that. It is better to use an http nodejs lib to make your own requests. The hardest part here is try to hold the very async nature of nodejs, since you might want first to create a folder, and then after successfully create it, create a file and then, at last, write or append data. Everything through http requests that you must send and wait the for answer to then go on....
At least node-webhdfs might be a good reference to you take a look and start your own code.
Br,
Fabio Moreira
I'm thoroughly confused on how to use an npm module in Meteor client code.
I understand modules like fs would only work server-side, but in this case I'd like to use a simple text module like this for displaying pretty dates:
https://github.com/ecto/node-timeago
I've tried installing the module under /public/node_modules,
and it works great on the server-side following these instructions from SO: (
How do we or can we use node modules via npm with Meteor?)
Meteor.startup(function () {
var require = __meteor_bootstrap__.require
var timeago = require('timeago')
console.log(timeago(new Date()))
...
However it doesn't work in the client-side code:
if (Meteor.is_client) {
var require = __meteor_bootstrap__.require
var timeago = require('timeago')
console.log(timeago(new Date()))
...
Uncaught ReferenceError: __meteor_bootstrap__ is not defined"
Server-side is sort of useless for me in this case, as I'm trying to render text on the client.
I don't believe you need to use the server side version. Use the npm stuff for server side only and btw, put it in your /public/ as well. Who knows maybe you can call it once it is in your /public/, try it. Or try this.
Use something like the jquery timeago.js
Put it in /client/ or something like /client/js
Create a /client/helpers.js or some such.
Use a handlebars helper.
Handlebars.registerHelper('date', function(date) {
if(date) {
dateObj = new Date(date);
return $.timeago(dateObj);
}
return 'a long long time ago in a galaxy far away';
});
Example of calling 'date' handlebars helper function from template.
{{ date created }}
Where date is the handebars helper and created is the date coming out of the meteor/mongo collection.
See the github Britto project. That is where I got this code snippet and used it in a chat room app I wrote. Works fine.
There are a couple of others floating out there. Go to madewith.meteor.com and peruse the source of some of the projects.