A Dropwizard bundle for providing clustered session replication using Hazelcast distributed maps.
Maven coordinates for the latest release are:
<dependency>
<groupId>com.unicodecollective.dropwizard</groupId>
<artifactId>dropwizard-hazelcast-session</artifactId>
<version>1.0.5</version>
</dependency>
See the example-app
module for a working example (more details below), but it comes down to this:
Add a HazelcastSessionConfig
property to your application configuration:
public class MyAppConfiguration extends Configuration {
@JsonProperty("hazelcastSessionConfig")
private HazelcastSessionConfig hazelcastSessionConfig;
public HazelcastSessionConfig getHazelcastSessionConfig() {
return hazelcastSessionConfig;
}
}
Most of the configs are optional, but you might want to set these in your YML config file:
hazelcastSessionConfig:
# Default is HazelcastSessionsStoreFactory
# sessionsStoreFactory: com.unicodecollective.dropwizard.hazelcast.session.HazelcastSessionsStoreFactory
# sessionsStoreFactory: com.unicodecollective.dropwizard.hazelcast.session.InMemorySessionsStoreFactory
sessionTimeoutSecs: 900
cookie:
name: myapp-session
hazelcast:
multicastGroup: 224.2.2.3
multicastPort: 54328
properties:
"hazelcast.io.thread.count": "1"
"hazelcast.event.thread.count": "1"
Add a HazelcastSessionBundle
to your bootstrap during initialisation:
public class DwHazelcastExampleApplication extends Application<DwHazelcastExampleConfiguration> {
// ...
@Override
public void initialize(Bootstrap<DwHazelcastExampleConfiguration> bootstrap) {
bootstrap.addBundle(new HazelcastSessionBundle<DwHazelcastExampleConfiguration>() {
@Override
public HazelcastSessionConfig getHazelcastSessionConfig(DwHazelcastExampleConfiguration configuration) {
return configuration.getHazelcastSessionConfig();
}
});
}
// ...
}
Annotate the resource field with @Session
to have the value injected from the Hazelcast-managed session:
package my.package;
import technology.zook.dropwizard.hazelcast.session.Session;
// ...
@Path("/")
@Produces(MediaType.TEXT_PLAIN)
public class MyResource {
@Session
private MySessionObject mySessionObject;
@Session
private AnotherSessionObject anotherSessionObject;
@GET
public String getSomething() {
return mySessionObject.getOne() + anotherSessionObject.getTwo();
}
}
Note
You session objects should be injected as fields into your Resource class using the @Session
annotation. There's currently a problem injecting them into request handler parameters.
Note
There appears to be a problem with declaring your Jersey resource in Dropwizard as an instance like this:
// Don't do this:
environment.jersey().register(new MyResourceClass());
While we figure out the problem you should declare your resource like this:
environment.jersey().register(MyResourceClass.class);
The example-app
module contains a working example of dropwizard-hazelcast-session
. It's a pretty terrible app, but what are ya gonna do...
Assuming you have a UNIX terminal with git and maven installed:
git clone https://github.com/martindow/dropwizard-hazelcast-session.git
cd dropwizard-hazelcast-session
mvn install
cd example-app
mvn package
java -jar server config/dw-hazelcast-example-dev-8180.yml
Now visit http://localhost:8180/ and you should see "Hello, Somebody!". Wonderful. Now submit a name using the form and you should be greeted appropriately. Reload the page a few times and you'll see the name sticks, as it's being read from the session.
To really appreciate the magic, however, you need to start a second instance of the server on another port (imagine these two nodes sitting behind a load balancer). When you do that Hazelcast will hook up with the second instance over multicast and will casually create you a cluster of "Hello, Somebody!" services.
So open a second terminal window in the same directory:
cd dropwizard-hazelcast-session/example-app
java -jar server config/dw-hazelcast-example-dev-8280.yml
Now visit that second web app in a browser: http://localhost:8280/ (note the different port). You should be greeted with the name stored in the first web app instance, which Hazelcast has synched over seamlessly. Change the name on one server and watch it replicate to the other server until you get bored.
Next up, open example-app/config/dw-hazelcast-example-dev-8180.yml
and example-app/config/dw-hazelcast-example-dev-8280.yml
and change the value of sessionTimeoutSecs
to 10
(seconds). Restart both services. Now you'll see the session expire after 10 seconds.
You can keep adding and removing nodes and Hazelcast will manage the cluster for you. Data will be transparently distributed across the nodes to ensure it will remain available if any node suddenly disappears.
Obviously a RESTful service shouldn't rely on session state to do it's work, so why would you want need this? Well Dropwizard Views offers a couple of great modules for building web applications and those often do need some session state to be useful.
dropwizard-hazelcast-session
lets you quickly and easily add session state which is instantly replicated across a cluster of services.
This project is released to the Sonatype OSS repository use Maven, the details of which are documented here:
http://central.sonatype.org/pages/apache-maven.html
- To release a snapshot version:
mvn deploy
- To release production version:
- Set the release version:
mvn versions:set -DnewVersion=1.0.3
- Set the release version of the example project:
cd example-app; mvn versions:set -DnewVersion=1.0.3; cd ..;
- Commit version change:
git add -A .; git commit -m "Setting the maven project version to xxx."
- Deploy the release version:
mvn clean deploy -P release
- Set the next snapshot version:
mvn versions:set -DnewVersion=1.0.4-SNAPSHOT
- Set the next snapshot version of the example project:
cd example-app; mvn versions:set -DnewVersion=1.0.4-SNAPSHOT; cd ..;
- Commit the version change:
git add -A .; git commit -m "Setting the maven project version to xxx."
- Set the release version: