Wednesday, October 30, 2013

Running Play 2.1.x App as Windows Service (Fat Free Version)


In this post, I'll show you how to run your Play 2.1.x app silently as a background service and give you a couple tools you can use to ease the administration process for your app. All of this without the use of third party tools.










For this tutorial we will use the Zentasks sample application that came bundled with the framework. This tutorial assumes that:

  • The zentasks project folder is located in C:\apps\zentasks
  • The Java executable is located at C:\Program Files\Java\jdk1.7.0_25\bin\

Adjust these directories to suit your needs. Let's get started.

The Problem


You have several apps that you need to deploy in a production Windows environment, but you hate having the pesky command prompt window visible in the background when you run play start for each application. You want your apps to run silently as Windows services on startup.

The Solution


Create a standalone distribution of your app by opening a command window and running

cd c:\apps\zentasks
play clean dist

In the dist folder of the application directory, you should see an archive named zentasks-1.0-SNAPSHOT.zip Extract the contents of that archive to the current folder.

In my case the location of my app is C:\apps\zentasks and the location of the folder I just extracted from the archive is C:\apps\zentasks\dis\zentasks-1.0-SNAPSHOT.

To run my app invisibly, I take advantage of the javaw.exe application bundled with my Java installation. This file does exactly what java.exe does but it does it in the background without showing a console window.

Note before continuing: Either turn off evolutions or set them to automatic in the application.conf file. You can do that by following the example here. Once that's done, run play dist again.

In a command prompt window I then run the following commands:
cd c:\apps\zentasks\dist\zentasks-1.0-SNAPSHOT
javaw -cp lib\* play.core.server.NettyServer

You'll notice that the command runs and returns you to the command prompt. Give it a couple seconds and go to http://locahost:9000 (or whatever port you set the app to run on) and see if your app is running. It should be.



Once you have that sorted out, let's move on. We're going to create two batch files for starting and stopping the application. Once these files are created we can also place them in the Startup folder on our Start menu to have them execute when Windows starts up.

Batch File #1: Start.bat


Open a Notepad document and paste in the following:
cd .
start "" "C:\Program Files\Java\jdk1.7.0_25\bin\javaw.exe" -cp lib\* play.core.server.NettyServer

Substitute the correct paths where necessary and save the file as start.bat in your application's dist\zentasks-1.0-SNAPSHOT directory.

To test the file, open task manager and kill the javaw.exe process,



then go to your application's dist\zentasks-1.0-SNAPSHOT directory and delete the RUNNING_PID file. Now double-click start.bat, wait a couple seconds then go to http://localhost:9000 to check if your app is up. It should be.

Batch File #2: Stop.bat

If starting your app in production mode is now that easy, then stopping it should be too.

Again, open a new Notepad document and paste in the following:
set /p pid=<RUNNING_PID
taskkill /PID %pid% /F
DEL RUNNING_PID

That information goes on three separate lines. Save the file as stop.bat, place it in your app's dist\zentasks-1.0-SNAPSHOT directory and when you run it, it should kill the javaw process that your app is running on and delete the RUNNING_PID file as well. To ensure that your app has been shut down, go to http://localhost:9000 and observe that your app is down. At the end of it all your directory structure is supposed to look as follows:

* zentasks  
 *-- dist      
 *-- zentasks-1.0-SNAPSHOT          
 *-- lib          
 *-- RUNNING_PID          
 *-- start.bat          
 *-- stop.bat 

You can now take this folder and plop it down on your production server worry-free. Yay!

Q&A 

But what about my configuration options? What if I want to change the port that the application is running on?
 Simple. In start.bat include -Dhttp.port=xxxx or any other configuration options before the -cp argument. E.g:

start "" "C:\Program Files\Java\jdk1.7.0_25\bin\javaw.exe" -Dhttp.port=9001 -Dconfig.resource=prod.conf -cp ...

Is starting the application this way safe?
As far as I can tell, yes. The long and short of the story is that the command you place in the start.bat file is what is essentially run when you execute play start plus or minus a few directory and Java option changes. +James Ward and the +Play Framework team are free to correct me on this if I'm wrong.

Where will the logs and other necessary files be created? A directory for logs will be created in the dist\zentasks-1.0-SNAPSHOT folder and an application.log file will be placed there. File system h2 databases will be placed in the dist\zentasks-1.0-SNAPSHOT folder.

Where does the application read configuration items from in this mode?
In the lib directory of dist\zentasks-1.0-SNAPSHOT  there is a file named zentasks_2.10-1.0-SNAPSHOT.jar If you were to extract the contents of this file, you'd see all the evolutions and *.conf files your created up to the point in time you ran the play dist command.

I hope this was helpful to you. Thanks to +James Ward and the amazing +Play Framework team for all their hard work, and as always thank you for reading.

Wednesday, October 16, 2013

Scheduling Jobs In Play 2

In this tutorial, I'll show you how to schedule asynchronous jobs in the Play! Framework version 2.1.3.

The Play! Framework has moved away from using Job classes with Crontab-like annotations for application level task scheduling. In place of the old model we find heavy use of the Akka system, which operates a bit differently and can take some getting used to if you're accustomed to the CRON/Quartz way of doing things.

Let's get started!

After creating our application, we need to create a Global.java file in the app/ directory. Place the following in the file:

import play.Application;
import play.GlobalSettings;
import play.libs.Akka;
import scala.concurrent.duration.FiniteDuration;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class Global extends GlobalSettings {
    @Override
    public void onStart(Application app) {
      //Magic goes here
   }
       
}

The above is nothing too complex. It's a file that contains code that will be executed upon starting the application. The important piece is the onStart method that has the @Override annotation. That's where we're going to place our scheduling code.

Before continuing, you should probably take a look at what the Play devs have to say about the use of their Akka scheduler before I give my personal explanation.

Place the following in the onStart method of the Global.java file we just created.

FiniteDuration delay = FiniteDuration.create(0, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(5, TimeUnit.SECONDS);

Runnable showTime = new Runnable() {
   @Override
   public void run() {
      System.out.println("Time is now: " + new Date());
   }
};

Akka.system().scheduler().schedule(delay, frequency, showTime, Akka.system().dispatcher());

The above simply allows us to log the current time to the console ever 5 seconds. Not very useful, but it's a start. Run the application and see for yourself.

schedule() Arguments Explained

Before we continue we should probably get a firm grip of the schedule(...) method signature.

delay - How long after the application starts should I wait before running my code?
frequency - After I've run my code the first time, how often should I repeat it?
showTime - A runnable containing the code that is to be run after the delay and at the defined frequency.
Akka.system.dispatcher() - Not entirely sure what this is, but it's needed as the last argument.

Neither of the first two arguments can be changed from within the Runnable body. The delay (and frequency) must be calculated on application start correctly and in such a way that the timing of the job is not affected by application restarts.

Defining a Proper Schedule

Now that we've covered the basics, let's move on to creating a useful schedule. The schedule that we'll create will run a task at 4PM every day.

The first step is to determine the delay i.e. how long the scheduler should wait to execute our task once the application has started. The challenge here is that the calculation of the delay must accommodate random application restarts. Say, for example, we start our application at 8AM, the job should wait roughly 6 hours before it starts, but if at 3PM the need arises for us to restart the application, the delay should be recalculated to 1 hour. We will calculate this delay in seconds for better precision.

I'll be using the Calendar class, but feel free to use JodaTime if you're more comfortable. So let's augment our previous code snippet to calculate this delay:
Long delayInSeconds;

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }
 delayinSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.

Code explanation:
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();

Use a Calendar object and set it's time to 4PM of the current day, then create a date object to store the current date and the intended start time based on the modified Calendar object.
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }

Find out the current date and time (now) and create a new Date object (nextRun) that will store the date and time of the next code execute.If the time now is after the time we planned to start the job, then we'll set the time that the job should execute to be tomorrow at 4PM. If not then we're on schedule and the nextRun will be today at 4PM.
delayInSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.


Next we do some simple subtraction to find out how many seconds between now and the next time the code should run. This is our delay... In seconds, of course.

From here on it's gravy. Simply substitute the delayInSeconds value for the integer value in the FiniteDuration delay variable and change the frequency to 1 day as follows:


FiniteDuration delay = FiniteDuration.create(delayInSeconds, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(1, TimeUnit.DAYS);
Runnable showTime ...
Altogether Now!

Long delayInSeconds;

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 16);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
Date plannedStart = c.getTime();
Date now = new Date();
Date nextRun;
if(now.after(plannedStart)) {
   c.add(Calendar.DAY_OF_WEEK, 1);
   nextRun = c.getTime();
} else {
   nextRun = c.getTime();
  }
 delayInSeconds = (nextRun.getTime() - now.getTime()) / 1000; //To convert milliseconds to seconds.

FiniteDuration delay = FiniteDuration.create(delayInSeconds, TimeUnit.SECONDS);
FiniteDuration frequency = FiniteDuration.create(1, TimeUnit.DAYS);
Runnable showTime = new Runnable() {
            @Override
            public void run() {
                System.out.println("Time is now: " + new Date());
            }
        };

Akka.system().scheduler().schedule(delay, frequency, showTime, Akka.system().dispatcher());

Now every day at 4PM your application will remind you of the time. Awesome.

Thanks very much to +James Ward and this magnificent post for helping me wrap my head around this tricky concept. Thanks to the +Typesafe folks for all their hard work with the +Play Framework , and as always thank you for reading.








Wednesday, October 02, 2013

How to Install Play 2 War: The Bare Minimum

In this post, I'll show you how to install the Play 2 War extension. This article describes the installation and configuration procedure for Play 2.1.x applications.

From the author: 
This project is a module for Play framework 2 to package your apps into standard WAR packages. It can be used with Servlet 3.0 and 2.5 containers (Tomcat 6/7, Jetty 7/8/9, JBoss 5/6/7, ...)
Step 1: Add the Plugin to plugins.sbt

Navigate to \project and open the plugins.sbt file. Add the following line to the end of the file:

addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "1.0")

Note: Be sure to include an empty line between this line and the previous addSbtPlugin statement.

Step 2: Add Play2War keys to Build.scala

In the same folder as plugins.sbt, you'll find the file Build.scala. Open this file and follow the template below for modifying it. Items in bold are the new lines that were added. Items in italics are items that can be modified to suit your application's needs.

import sbt._
import Keys._
import play.Project._
import com.github.play2war.plugin._

object ApplicationBuild extends Build {

  val appName         = "your_app_name"
  val appVersion      = "1.0-SNAPSHOT"

  val appDependencies = Seq(
    // Add your project dependencies here,
    javaCore,
    javaJdbc,
    javaEbean
  )

  val main = play.Project(appName, appVersion, appDependencies)
  .settings(Play2WarPlugin.play2WarSettings: _*).settings(
    // Add your own project settings here  
Play2WarKeys.servletVersion := "3.0"
  ).settings(
Play2WarKeys.targetName := Some("war_file_name")
  )


}

Tip: The full list of Play2WarKeys and their expected data types can be found here.

Step 3: Resolve Dependencies and Build the WAR

Open a command terminal and cd into your project's directory. Once there, run the following commands:

play
clean
dependencies
war

Once the war command has completed you can look in \target to see the generated WAR file. You can then take this file and deploy it to your servlet container of choice.

Why Would I Want to Use This Plugin?

That's a great question especially seeing that Play comes with its own high performance web server built in. My answer to that question is if you work in a Windows-centric environment like mine, you become acquainted with the "shortcomings" of the Play framework when it comes to production deployment in a Windows environment. Unlike Linux where you can easily set your application to run as a service in the background on startup, Windows forces you to resort to all sorts of .bat magic that leaves you with a bunch of command line windows popping up and having to stay open for the duration of the application's life.

So for a cleaner, less cluttered production server that other members of your team can appreciate, I recommend using a Servlet container like Tomcat that can be installed as Windows service and set to run on startup. No more .bat magic and no more freaking out when the server admin says he restarted the server a couple hours ago and now the folks in HR can't access the employee registration application.

Closing Remarks

In all, the installation of this extension was easy once you figured out how to switch mental context to deal with the different syntaxes for each file that has to be manipulated. I find that in some cases the author of the documentation could have gone into a little more detail in addressing the little gotchas with each file type. For example the need for an empty space between lines in the plugins.sbt file. Thankfully the Play command was smart enough to point this out to me when I tried to start the application and it was an easy fix.

That being said, though the installation of this particular plugin was not all that difficult, I would still like to see some more abstraction in the plugin installation process. I think the guys over at +Typesafe could take a very interesting page out of the Rails book in this regard.

That's it for now. I hope this article was useful.