Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play framework auto-loading in docker container

I'm trying to set up a development environment for developing a play application in a docker container. I have created an image with sbt installed. I then map the project folder on my host to the container as a volume and run shell in interactive mode:

docker run -v /Users/jorgen/dev/play-sbt-docker/app:/data/app -w /data/app -p 9999:9000 -i -t jorgenfb/sbt /bin/bash

I then starts the play application by running sbt ~run. The play server starts just find, it even recompiles when i edit my files on the host:

[info] Compiling 1 Scala source to /data/app/target/scala-2.10/classes...
[success] Compiled in 2s

The problem is that the changes does not appear in the browser when I refresh. There is no caching issue since I have disabled caching. If I run the application from my host, everything works fine.

Edit: This is my Dockerfile used to create the container with sbt:

FROM dockerfile/java:oracle-java8
MAINTAINER  Jørgen Borgesen

ENV SBT_VERSION 0.13.5

# Install sbt
RUN cd /tmp && \
    wget https://dl.bintray.com/sbt/native-packages/sbt/$SBT_VERSION/sbt-$SBT_VERSION.zip && \
    unzip sbt-$SBT_VERSION.zip -d /usr/local && \
    rm sbt-$SBT_VERSION.zip

I did some more research. Inside the docker container i start the play application like this:

[ root@aa1f2327d938:/data/app ]$ /usr/local/sbt/bin/sbt
[info] Loading project definition from /data/app/project
[info] Set current project to my-first-app (in build file:/data/app/)
[my-first-app] $ ~run

--- (Running the application from SBT, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

[success] Compiled in 740ms

Loading the page in my browser works fine. I then change my index file on the host. This triggers recompile inside the container:

[info] Compiling 1 Scala source to /data/app/target/scala-2.10/classes...
[success] Compiled in 1s

Refreshing my browser still shows the initial index file. Even if the changes was picket up by the play application inside the container. I have also inspected the compiled files in target/scala-2.10/classes/views/html (on my host, since I'm running the play application in the container and I'm not sure how to attach multiple terminals to it). The compiled files has changed.

The next thing I did was pressing Ctrl-D. This should take my back to the sbt console according the printed message above "(Server started, use Ctrl+D to stop and go back to the console...)". However this results in the following output:

[success] Total time: 455 s, completed Sep 25, 2014 7:40:35 AM
1. Waiting for source changes... (press enter to interrupt)

--- (Running the application from SBT, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

[info] play - Application started (Dev)

Now the changes I made earlier are reflected in the browser after a refresh.

like image 932
jorgenfb Avatar asked Sep 24 '14 16:09

jorgenfb


2 Answers

I solved the problem (sort of). The issue is not specific to either docker or play framework, but is related to how changes to files are detected using JNotify (play uses this library). Changes are detected by using native file system hooks. These hooks are not available in shared folders for virtual machines (I run the docker service in a VM machine since I'm on OSX). This means that the only way of automatically detecting file changes is to use a polling strategy. Play framework supports in version 2.3.2 and later. To enable, add this to your build.sbt:

PlayKeys.playWatchService := play.sbtplugin.run.PlayWatchService.sbt(pollInterval.value)

The answer is taken from an issue post on github: Play 2.3.2 auto reload is not working on shared folder

Update for play 2.4: Play 2.4 renames the config parameter. This is how to enable polling in 2.4:

PlayKeys.fileWatchService := play.runsupport.FileWatchService.sbt(pollInterval.value)

Thanks to philipphoffmann for his answer with the updated info. Added it to my answer to provide a solution for both 2.3 and 2.4.

Update: I just discovered a handy tool for OSX users: docker-osx-dev. It uses rsync to keep the host and virtual file systems in sync. This will trigger file system change on your virtual machine.

like image 135
jorgenfb Avatar answered Sep 23 '22 00:09

jorgenfb


For play 2.4 this would be:

PlayKeys.fileWatchService := play.runsupport.FileWatchService.sbt(pollInterval.value)
like image 25
philipphoffmann Avatar answered Sep 21 '22 00:09

philipphoffmann