Can't get os-service app working except from command line - node.js

I have a node.js app that I want to run as a windows service, and I'm using os-service to try to achieve that.
The service installs seemingly correctly, and the Windows Services management console provides this info about it:
In the listing:
Name: wibble
Description: (blank)
Status: (blank)
Startup Type: automatic
Log On As: Local System
In the properties/General pane:
Path to executable:
"C:\Program Files\nodejs\node.exe" "C:\path\to\app.js" "--run"
Attempting to start this service using powershell thus
Start-Service wibble
produces an error message containing: Cannot start service wibble on computer '.'
Attempting to start this service from the management interface's "Start the Service" link with the service selected in the Services manager yields a different error message: Windows could not start the wibble service on Local Computer. Error 1053: The service did not respond to the start or control request in a timely fashion.
The following works, when executed from a powershell in same folder as the app. Clients can connect to and use the app successfully:
node app.js --run
However, the powershell stops at that point until CTRL+C stops the service.
Here's the JS I added to the app to get it to run as a service:
var service = require('os-service');
var fs = require('fs');
process.chdir(__dirname);
if (process.argv[2] == '--run') {
var fn = process.env.LOCALAPPDATA + '/path/to/wibble.log';
var logStream = fs.createWriteStream (fn);
service.run (logStream, function () {
'use strict';
service.stop (0);
});
// rest of app here
}
module.exports = app
Hopefully I've overlooked something dumb. My gratitude if you can spot it!

Related

How to fix "Error: /home/site/wwwroot/node_modules/canvas/build/Release/canvas.node: invalid ELF header" on NodeJs Azure Functions in Linux?

I am trying to deploy an AzureFunctions in NodeJs but it doesn't work on Azure.
My apllication is a v3 functions running on Linux.
When the deploy is completed, i get this 500 error:
Error:
/home/site/wwwroot/node_modules/canvas/build/Release/canvas.node:
invalid ELF header
Its happen only when I do this imports:
import ChartDataLabels from 'chartjs-plugin-datalabels';
const canvasRenderService = new CanvasRenderService(width, height, chartCallback);
const chartCallback = (ChartJS) => {
ChartJS.register(require('chartjs-plugin-datalabels'))
};
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { document } = (new JSDOM(`...`)).window;
Would someone help me please?
It works (only) on my machine :(
Edit: It works when I make the deploy by Linux Subsystem.
I hope this will help somebody.
Azure function will not include the Node_modules while deploying into azure. Because Node_modules directory contains very large file. You can include your package.json in you function directory and run npm install as you normally would with Node.js projects using Kudu (https://<function_app_name>.scm.azurewebsites.net )or the Console in the Azure portal.
Check Dependency management for more information.
Refer here Link 1 & Link 2
Any updates on this topic?
Doesn't seem like a valid option for me to manually run npm install via KUDU or some other terminal in a Cloud Function App - especially with Continoues Deployment etc.
Got the same problem while using canvas for barcode generation...

How to pass the dotenv config path through a Windows service created with node-windows

Windows Server 2008 R2 Enterprise
Node version 12.13.1
node-windows version 1.0.0-beta.5
When I call my node application, instead of using require('dotenv') in code to load the environment variables (e.g. from a default .env file), I need to pass the path to a specific environment file. This environemnt file is different depending for which customer the application is started for (e.g. different database, paths, customer code, etc..).
In the cli, I can succesfully do it this way:
node --require dotenv/config bin/www dotenv_config_path=C:\projects\abc\env\XYZ.env
As you can see I use an absolute path for the location of the env file, but it also works with a relative path. I'm just trying to eliminate this as a reason why I can't make this work with node-windows.
I'm trying to use node-windows to create a Windows service wrapper that calls my node application and also loads a specific env file like the above code does. Can't make it work so far, after creating the Windows service, it quits after a moment, which tells me it's missing the environment variables it needs to function. Which means it can't load of find the environment file.
Here is my script to create the Windows service using node-windows:
#!/usr/bin/env node
// Usage:
// npm run install-win XYZ
// Notes:
// 1. Before creating the windows service, make sure to delete any previous files in the /bin folder (i.e. all files abcXYZ.*)
// 2. After creating the windows service, change the Log On account to the ******* user to avoid persmission issues when using paths on other production servers
const args = process.argv;
const codeclient = args[2];
const serviceName = `abc${codeclient}`;
const environmentPath = `C:\\projects\\abc\\abc-api\\env\\${codeclient}.env`; // Make sure to use the full absolute path here
const Service = require('node-windows').Service;
// Create a new service object
const svc = new Service({
name: serviceName,
description: serviceName,
script: require('path').join(__dirname, 'www'),
scriptOptions: `dotenv_config_path=${environmentPath}`,
nodeOptions: [
'--require=dotenv/config',
'--harmony',
'--max_old_space_size=4096'
]/*,
env: {
name: 'DOTENV_CONFIG_PATH',
value: environmentPath
}*/
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install', function(){
svc.start();
});
svc.install();
I've tried both the "scriptOptions" approach and the "env" approach in various configurations, but nothing works.
If anyone has managed to make something like this work before, I'd very much like to know how you did it.
So the way I ended up doing this is instead just pass my codeclient variable through the scriptOptions of node-windows, and then using that in my node application to have dotenv load a specific env file. It's more simple really.
The only issue I had with the approach is that node-windows would fail with my numerical codeclient, always assuming it's a number type instead of a string (node-windows tries to call String.split() on it later). I had to append the underscore in front to force it as a string.
Script to create the Windows service with node-windows:
#!/usr/bin/env node
// Usage:
// npm run install-win 123
// Notes:
// 1. Before creating the windows service, make sure to delete any previous files in the /bin folder (i.e. all files abc123.*)
// 2. After creating the windows service, change the Log On account of the service to the ******** user to avoid persmission issues when using paths on other production servers
const args = process.argv;
const codeclient = args[2];
const serviceName = `abc${codeclient}`;
const Service = require('node-windows').Service;
// Create a new service object
const svc = new Service({
name: serviceName,
description: serviceName,
script: require('path').join(__dirname, 'www'),
scriptOptions: `_${codeclient}`,
nodeOptions: [
'--harmony',
'--max_old_space_size=4096'
]
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install', function(){
svc.start();
});
svc.install();
Loading the env file in the node application:
// Load environment variables into process.env
if (process.argv[2]) {
// Load a specific env file for the codeclient passed as argument
const codeclient = process.argv[2].replace('_', '');
require('dotenv').config({ path: `./env/${codeclient}.env` });
}
else {
// Load the default .env file
require('dotenv').config();
}

Is there a way to automatically restart nodejs app after a 503 error?

My nodejs app keeps getting 503 resource exceed error every few weeks after running so I need to keep restarting it via ssh. I was wondering if there is something I can install to automatically restart it whenever I get an error or it crashes.
I have checked our A2Hosting server's number of processes during the error but it just says 0/50.
I am using pusher real time.
const express = require("express");
const router = express.Router();
const Pusher = require("pusher");
var pusher = new Pusher({
appId: "xxxxxx",
key: "xxxxxxxxxxxxxxxxxx",
secret: "xxxxxxxxxxxxxxx",
cluster: "ap1",
encrypted: true
});
router.post("/", (req, res) => {
const newVote = {
id: req.body.id,
points: 1
};
pusher.trigger("scan", "scan-player", {
id: req.body.id,
player_id: req.body.player_id,
admin_id: req.body.admin_id
});
return res.json({
success: true,
message: "Scan successful!",
id: req.body.id
});
});
module.exports = router;
An error should not get your app to crash, you should handle it and just log the error message. For example, with express error handler, see : error handling patterns with express
Also, if your app crash, some programs can restart it automatically. The most basic one is forever :
forever start app.js
It restarts your app when it crashes. But the best one in my opinion is pm2 :
pm2 start app.js
It does the same, but has a lot of additional functionalities, like load balancing, deployment system, log managment
Hope it helps,
Best regards
If you can configure cron jobs on your server then write a script which checks your logs for failure and restarts the app if it finds 503 error and attach the script to a cron job.
script can be like
if [ grep -q "503 or something specific" $logfile ]; then {
service $whatever stop;
service $whatever start;
} fi
If planning to try the cron job/script suggestion, then you would need to finally purge the log file after restart otherwise this would result in a restart loop.
There is a tool called logrotate which is cron implemented itself, you can add your own configurataion files to /etc/logrotate.d
IMHO the best option by far is pm2 as suggested. It really is the best and easiest of the process managers.

readFileSync throws error when server launched as linux service

i'm trying to make a simple api for myself using a node/express server running on digital ocean. in the server file i have something like this:
var data = fs.readFileSync('path/to/data.json','utf8');
which works perfectly fine when i launch the server manually from the cmd line
node server
but what i have setup is a linux service so that everytime i restart my digital ocean machine it will automatically launch the server, the service ( kept in etc/init/ ) looks like this:
start on filesystem and started networking
respawn
exec node /path/to/server.js
the issue is that when I make the request to the server that runs the readFileSync call it works fine if the server had been launched manually from the cmd line, but when the server was launched via the service then the readFileSync throws the following error:
Error: ENOENT, no such file or directory 'path/to/data.json'
at Error (native)
at Object.fs.openSync (fs.js:500:18)
at Object.fs.readFileSync (fs.js:352:15)
the file and the directory do exist ( if i make a request for the data.json file directly in my browser i can see it )
what am i missing? is there something about launching the server as a service that conflics with using readFileSync? is there an alternative approach to what i'm trying to do? should i use some kind of request/fetch resource module for accessing that json file?
You're using a relative path but the process is not being started from where you think it is. Instead of using relative paths, use absolute paths.
So if your layout looks like:
server.js
path/
to/
data.json
Then inside your server.js, you can just do something like:
var path = require('path');
// ...
var data = fs.readFileSync(path.join(__dirname, 'path/to/data.json'), 'utf8');

I have a very basic world koajs web app that i need to test on azure

I need to test koajs support on azure. since koajs uses --harmony flag with node to take advantage of generators its very hard to tweek node on azure.
following is the code for server.js file.
var koa = require("koa")
var app = koa();
app.use(function * () {
this.body = "Hello World!";
});
app.listen(80);
console.log("The app is listening. Port 80");
I have a web app on azure that use git local publising to push code online. how can i configure node to use --harmony switch?
You can control the node command line by using the nodeProcessCommandLine configuration setting which can be specified in an iisnode.yml config file as detailed in the "advanced scenarios" section of this post. This allows you to pass additional command line switches, choose your node version, point to your own deployed node build, etc.
For example:
nodeProcessCommandLine: "D:\Program Files (x86)\nodejs\0.10.18\node.exe" --harmony
Your specific issue is discussed in more detail in this github issue.

Resources