child_process.fork not starting an express server inside of packaged electron app - node.js

I have an electron app where I need not only to run the interface to the user but also start an express server that will serve files for people connected through the network.
I have everything working if I start both electron and the express server normally, but I'm pretty confident that I will need the server running in a different thread to avoid slugish interface and even problems with the server.
For that matter I tried to run my express server using the child_process.fork and it worked when I use npm start, but when I use electron-builder to create an .exe, the installed program doesn't start the express server.
I tried to run my server right away using:
require('child_process').fork('app/server/mainServer.js')
I tried several changes, prefixing the file with __dirname, process.resourcesPath and even hard coding the generated file path; changing the fork options to pass cwd: __dirname, detached: true and stdio: 'ignore'; and even tried using spawn with process.execPath, which will also work with npm start but won't when packaged (it keeps opening new instances of my app, seems obvious after you do hehe)
Note: If I don't fork and require the server script right away, using require('server/mainServer.js') it works on the packaged app, so the problem most like isn't the express itself.
Note 2: I have asar: false to solve other problems, so this is not the problem solver here.
I put up a small git project to show my problem:
https://github.com/victorivens05/electron-fork-error
Any help will be highly appreciated.

With the great help from Samuel Attard (https://github.com/MarshallOfSound) I was able to solve the problem (he solved for me actually)
As he said:
the default electron app will launch the first file path provided to it
so `electron path/to/thing` will work
in a packaged state, that launch logic is not present
it will always run the app you have packaged regardless of the CLI args passed to it
you need to handle the argument manually yourself
and launch that JS file if it's passed in as the 1st argument
The first argument to fork simply calls `process.execPath` with the first
argument being the path provided afaik
The issue is that when packaged Electron apps don't automatically run the
path provided to them
they run the app that is packaged within them
In other words. fork is actually spawn being executed with process.execPath and passing the fork's first argument as the second for spawn.
What happens in a packaged app is that the process.execPath isn't electron but the packaged app itself. So if you try to spawn, the app will be open over and over again.
So, what Samuel suggest was implemented like this:
if (process.argv[1] === '--start-server') {
require('./server/mainServer.js')
return
}
require('./local/mainLocal.js')
require('child_process').spawn(process.execPath, ['--start-server'])
That way, the first time the packaged app will be executed, the process.argv[1] will be empty, so the server won't start. It will then execute the electron part (mainLocal in my case) and start the app over, but this time passing the argv. Next time the app starts, it will start the server and stop the execution, so the app won't open again because spawn is never reached.
Huge thanks to Samuel.

Related

Child process (nodejs Express server) within packaged electron app not starting

I have a basic electron app (wrapping a Reactjs app) - everything works fine both in dev and when packaged.
Now I want to introduce a dependency, another basic nodejs express file server. I have written this file server and it works.
This file server is a nodejs module (so that it can be managed seperately). It is then required and spawn within the electron app as a seperate "child process".
Problem:
When I run "yarn start:dev", everything works perfectly but once I package this app(yarn pack:dev), everything works EXCEPT the file server(child process).
I believe this has something to do with the path and the fact that electron will bundle the entire app as "asar". I have tried different approach and exhausted of ideas.
I think the "asar" file path is not accessible or something. I have also disabled the asar in electron-builder.yml but still having same issue.
Please I will really appreciate any help. Thanks.

starting, stopping and restarting windows services using node js

Can someone explain how I can start or stop a windows service using a node program? Not a NodeJS service running on Windows, but specifically a Windows service itself, and that too, using NODEJS. There are lots of articles as to how to kill or start a NodeJS service, but not of what I am in need of here. There is an article though on StackOverflow in the following link:
Node js start and stop windows services
But I am either not doing it right because I have not understood it the way it should be or it doesn't do what I need it to do. Please help me out. Don't know why, but there are just almost no articles online about this.
USE os-services module
npm install os-service
It is loaded using the require() function:
var service = require ("os-service");
A program can then be added, removed and run as a service:
service.add ("my-service");
service.remove ("my-service");
service.run (function () {
// Stop request received (i.e. a kill signal on Linux or from the
// Service Control Manager on Windows), so let's stop!
service.stop ();
});
Use bat file to stop and start node server or user nodemon package.
And use windows task scheduler
#echo off
cd "D:\sam\Projects\NodeSchedule // path of node project i.e. index.js
taskkill /IM node.exe -F
start /min cmd /C "node index.js"
goto :EOF

App Dynamics for Angular 2 App in IIS - Node.js Agent Installation and Configuration

I am trying to assist in setting up AppDynamics with an Angular 2 app that is hosted in IIS. The app is already up and running. There is a part I am having trouble on, the instructions for that part say say:
1) From the root directory of your Node.js application, run this command:
npm install appdynamics#4.3.5
For every Node.js application you are instrumenting, insert the following call in the application source code at the first line of the main module (such as the server.js file), before any other require statements:
require("appdynamics").profile({
controllerHostName: '<controller host name>',
controllerPort: <controller port number>,
controllerSslEnabled: false, // Set to true if controllerPort is SSL
accountName: '<AppDynamics_account_name>',
accountAccessKey: '<AppDynamics_account_key>',
applicationName: 'your_app_name',
tierName: 'choose_a_tier_name',
nodeName: 'choose_a_node_name'
});
2) Restart you application
I did step 1 locally in the console, but I don't know what to do for step 2. If I add that script to the page I get "The Reference error: require is not defined".
I learned that that function is not meant to run on the browser. It's meant to be run server-side, but I do not see node js or any server.js files on our dev web server.
Does anyone have any suggestions on where to put that snippet. Will it even work with the current setup?
It turns out the code I was given was completely wrong for angular 2 implementation. The code they gave me is for running on the web server's side with node js. Since angular 2 is an SPA that runs on the browser, it would never work.
I did some research and found this example application that I added a few tweaks to: https://github.com/derrekyoung/appd-sampleapp-angular2

How to correct a Bluemix Node.js app that can't accept connections

I created a new Node.js app on Bluemix this morning and downloaded the boilerplate code. I worked on it locally and then pushed it up. On Bluemix, it refuses to start. The error according to the logs is:
Instance (index 0) failed to start accepting connections
So I Googled for that, in every case where I found the result, the answer was that my application was trying to use a specific port instead of letting Bluemix set it.
Ok, but I'm setting the host/port with the exact code the boilerplate uses:
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
So if this is incorrect, it means the code Bluemix told me to download itself is incorrect as well, and I can't imagine that is the issue.
To identify whether cfenv is at fault, I've tested that piece of code with a number of more complex Node.js apps I have, and they work perfectly on Bluemix.
That message can also come when an application you've deployed to Bluemix fails to start at all. Here's a few things you can do to troubleshoot your Node.js application on Bluemix.
Tail logs in another terminal while pushing with "cf logs
". Inspect logs after the failure to see if something
failed during the staging process.
Check that your start command in one of two recommended places, scripts.start in package.json or in a Procfile with web: node <start-script>.
Check that your application works locally. First (optional), create a .cfignore file with "/node_modules" in it, so that when you push the app to Bluemix, CF CLI doesn't push your entire folder of node_modules (as they will be installed dynamically). Next, wipe out your node_modules directory and do an npm install --production followed by npm start (or your custom start command). This is what Bluemix does when trying to start your application, so you should double check that it works locally.
Finally, try bumping up your memory, although this is very unlikely that this is why your application fails to start.

Flow of Work Working With Node.JS HTTP server

Learning Node.JS at the moment.
Everything is going fine, just that i have a little challenge with the flow of work.
So i create an HTTP server that listens at a particular port. For example
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
It works fine. Only problem is that when i edit the file that has the above code, and try to start the node process again by typing node server.js i get the following error:
Error: EADDRINUSE, Address already in use.
So i learnt I need to kill the node process using ps before the changes can be reflected and before i can restart.
But this looks like a pain. Do i need to kill the node process anytime i make changes to the server i am writing?
I am sure there is a better way. Any help?
During development I tend to just run node from the command line in a terminal window. When I'm finished with the testing I just Ctrl-C to interrupt the current process which kills node and then press arrow-up enter to restart the process.
my solution is as simple as
npm install dev -g
node-dev app.js
node-dev is the same as 'node' but automatically reruns app.js everytime any file in application dir (or subdir) is changed. it means restarting when static files are changed, too, but should be acceptable for development mode
There isn't any easy way. Authors of node do not like hot-reloading idea, so this is the way it works.
You can hack it if you put your server in a module, require it from the main script, fs.watchFile the .js for changes and then manually stop it as a reaction to a file change, manually deleting it from the module cache (require.cache if I am not mistaken), and require it again.
Or run it in child process and kill and respawn it after a file change (that is, doing automatically what you now do by hand).
You can use something like nodemon (video tutorial about it here) or node-supervisor so that the server auto-restarts when editing files.
If you want to manually do this, then just interrupt the process (CTRL+C) and re-run last command (node server.js).

Resources