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.
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
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, ✘ =
|#||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
|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
|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
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
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.
Packing a Rails application for production deployment is a specific process:
- Precompile assets
- Building a WAR file
- Package database scripts, CHANGELOG, and WAR file
- Submit application for validation
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
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
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.
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
gem 'jruby-jars', '=188.8.131.52' # Lock down our jruby version gem 'warbler','~> 2.0.4' # We need warbler to build our war file
Once installed, create
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
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
<?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,
#!/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
aboutmethod/action to the worklist controller and an associated route and view to show our version file and explain our application.
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
Service Notes. For the tutorial application, an excerpt from the
## 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`