Integrating FastBoot into an IIS shop?

I have a set of Ember client apps that will sit in directories served by IIS. Each one will be deployed as a website in IIS terms, although deployment of new versions is fundamentally no more than a file copy. I have a Web.config that will allow me to rewrite our /api requests to go to our API server. If Fastboot is running, it should be able to do a redirect to Fastboot as well to deliver our index.html as well.

What is the best way to integrate FastBoot into this environment?

  • Do we run a single FastBoot server running under Node providing pages for all the apps? Or do we run one per website - (one extra process per app)?

  • Can we tie initiation and shutdown of those processes with the lifecycle of the IIS website, so the admins remotely controlling the site through IIS donā€™t have to do anything special?

  • Is the code in our dist area sufficient to invoke directly from node to run the fastboot-app-server? Or does fastboot-app-server have to be installed separately in its own area? (What localhost:4200 does behind the scenes is kind of a black box to me. Iā€™m really happy it works for development.)

I want to get a protoype scenario running so I can schedule a meeting with our ops guys to figure out what is feasible on our site.

Beyond this, I havenā€™t even scratched the surface of what this means in the context of Akamai and Alteon fronting our site. Thatā€™s a whole other kettle of fish, but I could use advice on that, too, so I can at least talk intelligently with our ops guys.

Thanksā€¦

Hoping that by chronicling my journey here, I may get helpful hints along the way, hereā€™s where Iā€™ve gotten so far.

The first step was relatively easy. I made a directory, cut/pasted the server.js from the fastboot-app-server github site, and made a minimal package.json that listed fastboot-app-server as a dependency. A quick trip through yarn, editing the server.js to point it at my iis-dist area (which is both a subdirectory of my project, parallel to dist, and a virtual directory under IIS), node server.js and up she comes on http://localhost:4000. Grand!

Looking at the results in the browser, I can see that the page is there but it is having trouble finding most of my assets - like CSS. Itā€™s there, but ugly. The CSS files and images donā€™t worry me much, because the URLs will work fine when coming through IIS, but the config files do, as I want their contents in my shoebox. The sole objective of FastBoot is delivering that ready-to-rock index.html file. Hmmmā€¦

The difficulty stems from rootURL. My application is on an IIS site with ARR rewrites upstream. This means that URLs from the browser of the form:

http://mainsite/toolsprefix/{locale}/{toolname}

end up getting sent to

http://{toolname}-server/{locale}/{toolname}

When loading the site from the browser, supplying a rootURL of /toolsprefix and including {locale}/{toolname} in the route so the client can use the locale, everything comes up fine.

However, running in localhost:4000 in the browser, FastBoot, which has picked up the rootUrl from the build, canā€™t seem to find any of the collateral files on /toolsprefix/{locale}/{toolname}. It wants them on /{locale}/{toolname}. I tweak the ā€˜rootUrlā€™ in the package.json in the iis-dist to /, and everything comes up fine. However, this is not a sustainable solution.

Next problem: I add an ARR rule on the IIS server to rewrite incoming requests for /myprefix/{locale}/{toolname} to the FastBoot server on port 4000. (Iā€™m already using a rewrite for other resources to strip off the /myprefix.) After a little tinkering with the rule, I now am able to navigate to http://myserver/myprefix/{locale}/{toolname}. I can see FastBoot doing its work to deliver the index.html page and reporting it successfully read the configs, I can verify that the FastBoot page shows up in the browser with shoebox intact, and everything comes up, working beautifully.

Not bad for an early afternoon. Remaining interesting problems:

  • Setting up access during the build so that FastBoot can find everything it needs to create the index.html with the config resources in the shoebox, but direct access to all assets from the browser via IIS still works fine.

  • IIS will need a module that starts ā€œnode server.jsā€ when the web app is started and stops it when the web app is stopped remotely from the IIS management console. I could perhaps try to use IISNode, but it seems like it will try to do things that fastboot-app-server is already doing, like making more servers.

Any insight on either of these will be appreciated.

When I get all this working and present it to folks on the ops team, :slight_smile: there will inevitably be a whole slew of things to work out with the production infrastructure, CDN, caching, load balancing, etc., etc. But thatā€™s fine. Iā€™ll have something functioning that we can make better.

Next stop in the journey - I did look into IISNode, and was able to use it to get some services running. I even went to some effort to plumb the path to the named pipe that IISNode uses in lieu of a TCP host and port.

However, when firing up fastboot-app-server, we get ENOTSUP on each of the workers. After several hours of learning the basic tricks for Node debugging of multiple processes, I discovered the root cause. From the Node Cluster documentation (Cluster | Node.js v21.2.0 Documentation):

Please note that on Windows, it is not yet possible to set up a named pipe server in a worker.

FastBoot uses clusters so your app isnā€™t tied to one processor. After a very little further research, I ran into the following in one of the IISNode issues:

Cluster is not supported by iisnode. Cluster module allows load balancing TCP traffic across several processes. In case of iisnode, the listener is established over named pipes as opposed to TCP, and hence is not supported by cluster (iisnode uses HTTP over named pipes for communication between IIS worker process and node.exe).

However, iisnode has a functionality corresponding to cluster built in. You can choose the number of node.exe processes iisnode will create per application and load balance the traffic across using the nodeProcessCountPerApplication configuration setting.

(from error when use cluster Ā· Issue #195 Ā· tjanczuk/iisnode Ā· GitHub)

Itā€™s always much easier to find answers after you know whatā€™s really happeningā€¦ :wink:

So, unless and until fastboot-app-server supports optionally operating in a non-cluster, single worker mode for support of pipes on Windows (or iisnode is able to operate via a TCP connection), it looks like this combination is a non-starter.

Do you think your work would be willing to have you spend the time to build that? Itā€™d be great to get that support rolled in so future IIS shops can use it too, but most folks donā€™t have the setup you do, so it may not land without some help ā€¦

Yikes! You could try creating your own express app with the fastboot middleware. https://github.com/ember-fastboot/fastboot-app-server/blob/master/src/express-http-server.js#L54

Intriguing - since it is the fastboot-app-server module that does all the clustering, youā€™re saying I can:

  • create an instance of the small express app provided by fastboot-app-server module.
  • Pass it an instance of the primary object of the fastboot-middleware module
  • Pass the named pipe to the fastbootExpressApp , which should be able to consume it.

Did I get that right? Thatā€™s brilliant! All the pieces are already there. It shouldnā€™t take a lot of time to put together. I can try that. Iā€™ll report back.

Looking ahead, if that works, itā€™s a pretty generic solution. Picking up on the question by @acorncom, after some experimentation and measurement to be sure it works well at least at moderate speed and scale with a set of iisnode instances, I could encapsulate it in a ā€œfastboot-noncluster-app-serverā€ object that could also be supplied in the fastboot-app-server module. Then we could add a section to the readme showing a sample server.js file for the iisnode configuration.

Proceeding along the lines set out by @ryanto, I quickly figured out that my code was starting to look pretty familiar - identical code was already in the fastboot-app-server project. Stepping back, I was able to supply a very small and controlled set of changes to the fastboot-app-server class, so that, with a workerCount of -1, it doesnā€™t attempt to cluster. It just runs the worker in the master thread. Using this approach, I was able to get my FastBoot server running under IISNode this afternoon. Making threads is now IISNodeā€™s job.

Before I submit a PR, I need to fix one issue. Iā€™m not getting a reload when a new version of the project is loaded, and I think itā€™s because the IIS cache isnā€™t getting flushed, so the server isnā€™t even getting called again. Happily, I think I just need my server.js to make use of hooks already provided by the fastboot-api-server to tell outside caches its time to flush themselves. It is possible, though, that I missed something in the reload logic, so Iā€™ll fix this first - then Iā€™ll submit the PR.

3 Likes