In this section, you will review the standards an application must meet before it is ready for validation or can be deployed to a production server. It will also provide guidance on how to package an application in the mandatory format.

Prerequisites

It is helpful to understand a J2EE environment. By way of example, understanding that a Rails application will be running in multiple and independent threads (unlike the Rails server).

You may also want to have a clear understanding of the Rails asset pipeline and how precompiled assets work and are delivered.

Preparing for production

Production Checklist

Before an application can be distributed and deployed, it needs to be validated. To ensure that an application passes validation, it must comply with the App Validation guidelines. The tutorial application focused on teaching Bridge concepts, rather than making a production-hardened, highly configurable application.

Improvements for the Tutorial App

Here are some example issues that would need to be addressed:

✔ = Passes Validation, ✘ = Fails Validation

# Validation Goal Validation Results Feedback
5 There are no queries that take an excessive amount of time to return or put an unacceptable load on the system. If there are unconstrained queries (no limits, no where, etc.), there needs to be a well-reasoned argument for why this behavior should be accepted. The worklist query, while it may work in some test environments, would likely yield a larger result set than expected in a real deployment. Reasons range from data quality issues to large-scale, multi-facility installations where a single instance covers multiple time zones and millions of patients. Any of these would create a query that requires more memory than the environment, resulting an a crash.
11 Values that are not platform-managed cannot be hard-coded and must be configurable via an administrative interface in the application. By way of example, a platform-managed value set would be clinical_roles, a non-managed value set would be modalities. The full list of platform-managed values is enumerated in the Service Tools application under the Reference heading of the Data Browser tab. The email from address is hardcoded, the sending of email is not optional
13 Interfaces to other APIs or external systems must not have credentials embedded in the application, similar to #11. By way of example, if an app displays location data using the Google Maps API, the API key must be a configuration variable not hardcoded into the application. The email api_key is hardcoded
14 If the application has a database schema for storing app-specific information, all tables must have a primary key. Any tables queried must have columns appearing in a where clause indexed. Additionally, timestamp data must use the column type timestamp with time zone and foreign key reference columns must use the bigint type. Table and other object names must be prefixed with the application name or a similar abbreviation. The rails_developer_tutorial_notes table has two fields that are used in a WHERE clause, but not indexed (employee_id,rad_exam_id)

Implementing pagination on the worklist (using a limit and offset in the query) solves #5 (although it is complicated by the real-time data). Creating an admin page that only employees in the ai-staff and it-staff roles can access to edit the from and the api_key values, and toggle email sending addresses #11 and #13. Creating the missing indexes fixes #14.

Packaging

Packing a Rails application for production deployment is a specific process:

  1. Precompile assets
  2. Building a WAR file
  3. Package database scripts, CHANGELOG, and WAR file
  4. Submit application for validation

Further detail about the packaging requirements

Precompiling Assets

The Rails asset pipeline handles images, CSS, and JavaScript and offers compression and packaging utilities out of the box so that there is less overhead on page loads. When using the asset pipeline (on by default), ensure that all assets are precompiled before building the WAR file.

The production deployment will be in a relative root environment (http://server.example.com/example-app/), so that path must be passed to the rake task that precompiles assets. The application name needs to be globally unique and approved by AI. The command to precompile assets:

RAILS_RELATIVE_URL_ROOT="/railsdevelopertutorial" \
RAILS_ENV=production bundle exec rake assets:precompile

Confirm that all assets have been precompiled by looking in the public/assets directory of the Rails application root. Anything required in the application.js should should be manually verified by viewing the application.js file created there.

Ensure any of the independently included assets (e.g.) files in the app/assets/javascripts/pages directory) are also there. Since Rails version 4.2, development configuration is set up so that these files are required properly in config/initializers/assets.rb or the page will error out (previous versions of Rails assets could be there in development, but not in production).

If you don't clean assets (rake assets:clean) they will be used by the application when in development mode (instead of getting the new versions you are editing).

Setting up the WAR file configuration

Before creating the WAR file, set the production secret_token_base. Generate a secret by running rake secret. Use that output as the value for production in config/secrets.yml.

To create a WAR file, save the application name. Create the file config/application.name with only the application name as a single string. This will be the URL of the relative root of the app, e.g. http://server.example.com/example-app

Web applications are deployed with the J2EE web application archive packaging structure. To build a Rails application into a WAR file, install the warbler gem (gem install warbler) and include in the Gemfile:

gem 'jruby-jars', '=9.1.5.0' # Lock down our jruby version
gem 'warbler','~> 2.0.4' # We need warbler to build our war file

Once installed, create config/warble.rb:

Warbler::Config.new do |config|
  app_name = File.read(File.join(File.dirname(__FILE__),"application.name")).strip
  config.jar_name = app_name
  config.webxml.jruby.min.runtimes = 2
  config.webxml.jruby.max.runtimes = 10
  config.includes = FileList["init.rb"]
  config.webinf_files += FileList["jboss-deployment-structure.xml"]
end

This configuration sets options for warbler to use when building the WAR file. The last option refers to a file that needs to be created to resolve an issue with classloader finding gems included with JRuby. Create init.rb:

$LOAD_PATH.unshift 'uri:classloader:/META-INF/jruby.home/lib/ruby/shared'

This will run in the start up sequence of the application in the J2EE deployment environment.

Next we need to add the jboss-deployment-structure.xml. This should be in the root of your rails project. It instructs wildfly to include the harbinger.sdk module:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
  <deployment>
    <exclude-subsystems>
      <subsystem name="jpa" />
    </exclude-subsystems>
    <dependencies>
      <module name="harbinger.sdk" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

With the configuration in place, the WAR package can be made with the command RAILS_ENV=production bundle exec warble war.

Warning - Warbler will put everything found in the basic Rails directories, including files not committed in version control, into the WAR file it builds. If you have unused views or other code stubs residing in the app/ path, remove them before building or use the best practice.

Generating the WAR file

Create a bash script to combine asset precompiling and WAR building into a single bash script at the root of the application, warbilizer.sh:

#!/bin/bash

APPNAME=`cat config/application.name`

# Standard file changes
echo "Warblizer: Creating version page"
git describe --always > app/views/worklist/_version.html.erb

# Warbalizing with changed files

echo "Warblizer: Bundling"
RAILS_ENV=production jruby -J-XX:MaxPermSize=256m -S bundle install --path=target

echo "Warblizer: Pre Cleaning Assets"
ASSETS="clean" RAILS_ENV=production jruby -S bundle exec rake assets:clean

echo "Warblizer: Precompiling Assets (this takes a while)"
ASSETS="precompile" RAILS_RELATIVE_URL_ROOT="/$APPNAME" RAILS_ENV=production jruby -J-XX:MaxPermSize=256m -S bundle exec rake assets:precompile

echo "Warblizer: Building War File"
WARRING="warbilizing" RAILS_ENV=production bundle exec warble war

echo "Warblizer: Post Cleaning Assets"
ASSETS="clean" RAILS_ENV=production jruby -S bundle exec rake assets:clean

echo "Warblizer: Changing permissions and war file name"
chmod +r "$APPNAME.war"
mv -v "$APPNAME.war" "$APPNAME.war.`git describe --always`"

# Resetting standard files
git checkout app/views/worklist/_version.html.erb

Best Practice - Package applications from a fresh clone from the source control system to prevents uncommitted code from being included in an application.

This script uses the config/application.name file to drive all the commands that will precompile assets, WAR the application, clean the precompiled assets, and set up the version partial. The version is determined using git describe.

Best Practice - All applications should have a version. While not a requirement at the present time it will be in the future. This version should be visible in a deployed application. Using git tags and semantic versioning is recommended.

We use git tags to identify our releases and git describe takes this into account; resulting in a clean version name without having to maintain a version file.

Note - The version/about page is implemented with an about method/action to the worklist controller and an associated route and view to show our version file and explain our application.

CHANGELOG

Applications should have a CHANGELOG.md file to describes the changes from version to version. Additionally, requests for things like cron entries and any database migrations that need to run should be in subsections of your CHANGELOG.md labelled Service Notes. For the tutorial application, an excerpt from the CHANGELOG.md:


## v0.9.0 released 2015-10-19

The initial development release for a real time worklist application. The features include:

* Show all completed exams in a table in real time (no server polling)
* Authentication and authorization using Single Sign-On
* Centralized HIPAA Auditing
* Centralized application usage logging
* Launching an image viewer
* Adding notes to an exam and updating them in real time (no server polling)
* Alerting users with email when an exam is still in completed status and is older than a given threshold

### Service Notes
Database installation required:

`./db_scripts/install.sh`