Node app and cfexecute

Hi,

I wonder if any of you have tried to run a simple node app via cfexecute call.
Well, I tried with
<cfexecute name="#path#/javascript/node myapp" arguments="#arg1# #arg2# #arg3#" variable="getResult"></cfexecute>
produces nothing while no error in the meantime.
Or is it not the correct way to call cfexecute for running a node app?

fyi, npm install has been run, in other words,
node app #arg1# #arg2# #arg3#
runs fine at command line

Notes: of course all the vars above have been defined.

Thanks.

I’ve not tried this, but I believe myApp would need to be passed as an argument too, as it technically is an argument to the node.

If you are expecting a result, i.e. the variable section, you need to add a timeout otherwise it executes the call in the background.

1 Like

Good to know, thanks.

In the meantime, neither of the following options for arguments works, am I still missing something?

arguments='"myapp" "arg1" "arg2" "arg3" "arg4"'
arguments='"myapp","arg1","arg2","arg3","arg4"'
arguments="myapp,arg1,arg2,arg3,arg4"
arguments="myapp arg1 arg2 arg3 arg4"

I’d assume it should be the last one. As node is being called and then the arguments attribute is passed in… So option 4 would result in

node myapp arg1 arg2 arg3 arg4

When you say doesn’t work, if you run the command from a shell, what do you see/get? If you run from Lucee and dump the result, what do you get?

1 Like

dump resulted in
"
cfexecute error:
Error invoking external process
"
running node code from command line produces desired output.

thanks.

If there is an error it will dump to stderr and not stdout. In CF stderr gets dumped into errorVariable and stdout gets dumped into variable. Try adding the errorVariable to your call - that may at least help point you in a direction.

HTH

– Denny

1 Like

too bad.
"
cfexecute error:
Error invoking external process
"
persists
and both variable and errorVariable dump nothing.

[LDEV-1627] - Lucee - suggests this error can happen if you do not have the full path to the javascript. I’d evaluate what your #path# var equates to and ensure that is actually the full path to node.

Also, since you’re using Ubuntu iirc please note that node is actually an alias to nodejs - so try it with nodejs as well.

HTH

– Denny

1 Like

hmm it’s not node vs nodejs
I sort of simulated the cfexecute with the command line,
if I run /home/myuserid/lucee5/www/allapps/javascript/node myapp
it fails
but

cd  /home/myuserid/lucee5/www/allapps/javascript/
node myapp  (default without parameters)

runs fine.
so, I created a shell script that reads:

cd  /home/myuserid/lucee5/www/allapps/javascript/
node myapp $1 $2 $3 $4

THAT shell script runs fine at command line either
/home/myuserid/lucee5/www/allapps/javascript/myscript.sh
or
./myscript.sh

so, I tried name=" /home/myuserid/lucee5/www/allapps/javascript/myscript.sh"
and name=“./myscript.sh” respectively for the cfexecute,
however,
the dreaded
"
cfexecute error:
Error invoking external process
"
persists.

I assume you’re still using lucee in a container… so… is nodejs also in your container?

1 Like

Yes, lucee is in a container, it’s a docker image,
nodejs has been installed on the Ubuntu but not as docker image,
and the particular node app comes with a blockchain platform called Hyperledger Fabric, which has a bunch of docker images including one called “fabric-nodeenv”, not sure how exactly the installed nodejs package and this “fabric-nodeenv” interact with each other.

Thanks.

Then you can’t expect lucee to cfexecute it. :). The executable isn’t in the container lucee is.

You can see where node is with ‘which node’, it’s probably in /usr/bin/. If you do a fileexists(“/usr/bin/node”) in lucee it will return false.

1 Like

which node returns
/home/myuserid/.nvm/versions/node/v8.15.1/bin/node
so, I’ve made changes for the program path and name accordingly below
<cfexecute name="/home/myuserid/.nvm/versions/node/v8.15.1/bin/node" arguments="--version" variable="getCoin" errorVariable="stuff" timeout="4"></cfexecute>

however,
it resulted in
"
cfexecute error:
Error invoking external process
"
again.

In the meantime, thanks for leading me to think in this direction. now it seems I need to solve three problems here.
the first, ensure that lucee can launch node;
then, the specific node app can be loaded by such node launch;
and then, passing the parameters correctly to them.

Correct on the 3 problems.

You’d essentially have to create your own derivative docker container for lucee. From your post Apr 20 you’re using Lucee 4.5? I know there were cfexecute items fixed in Lucee 5.3 but I have no idea about Lucee 4.5. (insert usual response here on 4.5 isn’t supported, people aren’t going to have experience with it, the container isn’t being updated, you should really be on 5, blah blah blah)

Lets figure out what the container is using assuming your’e using lucee/lucee4:latest

$ docker run --rm -it lucee/lucee4:latest cat /etc/os-release

PRETTY_NAME=“Debian GNU/Linux 9 (stretch)”

NAME=“Debian GNU/Linux”

VERSION_ID=“9”

VERSION=“9 (stretch)”

ID=debian

HOME_URL=“https://www.debian.org/”

SUPPORT_URL=“https://www.debian.org/support”

BUG_REPORT_URL=“https://bugs.debian.org/”

Cool, stretch.

https://github.com/nodesource/distributions#deb

(note that Node 8 is old too)

That page says to do


Using Debian, as root

curl -sL https://deb.nodesource.com/setup_8.x | bash -
apt-get install -y nodejs


So we do that in a Dockerfile.

I.e. create a Dockerfile in a new, empty directory:


FROM lucee/lucee4:latest

RUN apt-get update && \

apt-get install -y --no-install-recommends curl && \

curl -sL [https://deb.nodesource.com/setup_8.x](https://deb.nodesource.com/setup_8.x) | bash - && \

apt-get install -y nodejs && \

apt-get clean

Now:

docker build -t lucee4-nodejs:latest .

It’ll go through and do the install and return a “Successfully built …” line.

Verify the results:


$ docker run --rm -it lucee4-nodejs:latest nodejs --version

v8.16.0

$ docker run --rm -it lucee4-nodejs:latest which nodejs

/usr/bin/nodejs

Replace your current docker run (or docker-compose) image for your lucee server with lucee4-nodejs:latest and restart the container.

now FileExists(“/usr/bin/nodejs”) should return true, and you can cfexecute things.

Personally were I to use cfexecute I’d ensure my arguments were properly encapsulated in an array. i.e.


<cfset args = [ "/path/to/my/file.js", "arg1", "arg2", "arg3" ] />

<cfexecute name="/usr/bin/nodejs" arguments="#args#" timeout="10" variable="nodeOut" errorVariable="nodeErr" />

or similar.

Be sure the paths you enter are for the CONTAINER, not the host. (i.e. if /home/youruser/lucee5/allapps is mapped to /app, you want /app instead)

If you’re using Lucee 5’s nginx container it’d be the same process.

From the 5.2 container:


docker run --rm -it lucee/lucee52-nginx:latest cat /etc/os-release

PRETTY_NAME="Debian GNU/Linux 9 (stretch)"

NAME="Debian GNU/Linux"

VERSION_ID="9"

VERSION="9 (stretch)"

ID=debian

HOME_URL="[https://www.debian.org/](https://www.debian.org/)"

SUPPORT_URL="[https://www.debian.org/support](https://www.debian.org/support)"

BUG_REPORT_URL="[https://bugs.debian.org/](https://bugs.debian.org/)"

Also based on stretch. So the above Dockerfile is correct, just change the from line.

Also note that once you do this, you’re responsible for periodically rebuilding your container if the source container updates. (Currently you’d just docker pull and restart your container, instead, you’d now need to docker pull and if a new version is pulled, rebuild your LOCAL lucee4-nodejs:latest or lucee52-nodejs:latest or whatever you want to call it)

The better way to do this would be to use a more microservices based approach. If your node app is based on the command line, you’d wrap it in a HTTP wrapper or a unix socket based wrapper and use a volume mount to compose your services together. (i.e. use nodejs’s Express to attach a HTTP api. Or use something like fcgiwrap and use a fastcgi socket. Or something like ucspi-unix) Then updates for each container happen independently. That may be beyond your abilities at the moment. I can’t give more specifics without knowing exactly what you’re trying to accomplish and how the pieces are built.

Very informative, Joe, much appreciated.

my nodejs version: v8.15.1
lucee version: 5.2

And I like your following cfexecute example,

<cfset args = [ "/path/to/my/file.js", "arg1", "arg2", "arg3" ] />

<cfexecute name="/usr/bin/nodejs" arguments="#args#" timeout="10" variable="nodeOut" errorVariable="nodeErr" />

prior to applying it to my case I definitely want to make sure lucee is able to call node and to return its version to start. Thus, my previous attempt of
<cfexecute name="/home/myuserid/.nvm/versions/node/v8.15.1/bin/node" arguments="--version" variable="getCoin" errorVariable="stuff" timeout="4"></cfexecute>

cat /etc/os-release
NAME=“Ubuntu”
VERSION=“16.04.6 LTS (Xenial Xerus)”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=“Ubuntu 16.04.6 LTS”
VERSION_ID=“16.04”
HOME_URL=“http://www.ubuntu.com/”
SUPPORT_URL=“http://help.ubuntu.com/”
BUG_REPORT_URL=“Bugs : Ubuntu”
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

create a Dockerfile in a new, empty directory: DONE with your exact code.

docker build -t lucee52-nodejs:latest .
resulted in
[WARNING]: Empty continuation line found in:
RUN apt-get update && apt-get install -y --no-install-recommends curl && curl -sL https://deb.nodesource.com/setup_8.x | bash - && apt-get install -y nodejs && apt-get clean
[WARNING]: Empty continuation lines will become errors in a future release.
Step 1/2 : FROM lucee/lucee52-nginx:latest

Executing 1 build trigger

—> Using cache
—> 69512fb0ef50
Step 2/2 : RUN apt-get update && apt-get install -y --no-install-recommends curl && curl -sL https://deb.nodesource.com/setup_8.x | bash - && apt-get install -y nodejs && apt-get clean
—> Running in 87ceaed0d42f
/bin/sh: 1: Syntax error: “(” unexpected
The command ‘/bin/sh -c apt-get update && apt-get install -y --no-install-recommends curl && curl -sL https://deb.nodesource.com/setup_8.x | bash - && apt-get install -y nodejs && apt-get clean’ returned a non-zero code: 2

Thanks.

The forum mangled the syntax. See here:
https://gist.github.com/goochjj/36b7e0f69cf1e0e8fb69ad823ffb4f23

It’s entirely possible that node won’t be enough, you may also need dependent node_modules… maybe you can use the ones from the host but that wouldn’t necessarily be best practice.

It may be way easier to use commandbox to launch lucee servers in your host environment then to do a lucee docker container…

1 Like

After fixing the syntax error,
docker build -t lucee52-nodejs:latest . runs,
however,
docker run --rm -it lucee52-nodejs:latest nodejs --version encountered an error,
"Unable to find image ‘luceee52-nodejs:latest’ locally
docker: Error response from daemon: pull access denied for luceee52-nodejs, repository does not exist or may require ‘docker login’.
"

How would commandbox solve this problem?

Thanks Joe.

There are 3 e’s in your error. You spelled it wrong.

Commandbox would allow you to run a Lucee server in a jvm on your host, so you can develop faster since you can use the nodejs and other binaries directly from your host.

1 Like

My bad for the typo. So, yeah, so, now,
the cfexecute call for the nodejs and then pass the " --version " parameter works.
However, passing “mypath/nodeApp.js” failed because you’re exactly correct in the following
“It’s entirely possible that node won’t be enough, you may also need dependent node_modules”

Sorry, I’ve never used Commandbox, could you please be more specific for this case?
Thanks you very much Joe.

  1. Install commandbox
    https://www.ortussolutions.com/products/commandbox

  2. Go to the root of your web app and type box server start. The default engine should be Lucee 5, and will start up a server on localhost, on a random port.

You maybe wish to do a more involved command line, i.e.

box server start host=0.0.0.0 port=8080 openbrowser=false rewritesEnable=true cfengine=lucee@5

Refer to box help server start, and https://commandbox.ortusbooks.com/, and/or #commandbox on boxteam slack - but it’s not that hard to work with.

1 Like