Recently, I wrote a RESTful web service in Java 8 using Dropwizard.
I like Dropwizard's simple, lightweight, getting-things-done attitude. In this post I will demonstrate how to combine Dropwizard's Managed
objects with Guava's concurrency primitives to write simple background tasks for your service
The Specifics#
Guava provides com.google.common.util.concurrent.AbstractScheduledService
,
an abstraction for a periodic task that runs on its own background thread
at user-defined intervals and can be started and stopped from the main thread. Here is one that logs to the console every 5 seconds
package com.kountanis.dwex1.core;
import com.google.common.util.concurrent.AbstractScheduledService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
public class ConsoleLoggingScheduledTask extends AbstractScheduledService {
private final Logger LOGGER = LoggerFactory.getLogger(ConsoleLoggingScheduledTask.class);
@Override
protected void runOneIteration() throws Exception {
LOGGER.info("runOneIteration");
}
@Override
protected AbstractScheduledService.Scheduler scheduler() {
return AbstractScheduledService.Scheduler.newFixedRateSchedule(0, 5, TimeUnit.SECONDS);
}
}
Dropwizard provides the Managed
interface for objects that need to
be started and stopped when the application instance is started or stopped.
It is easy to create a container/adapter for an AbstractScheduledService
subclass like the one above and have it managed by Dropwizard.
package com.kountanis.dwex1.core;
import com.google.common.util.concurrent.AbstractScheduledService;
import io.dropwizard.lifecycle.Managed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ManagedPeriodicTask implements Managed {
private final Logger LOGGER = LoggerFactory.getLogger(ManagedPeriodicTask.class);
private final AbstractScheduledService periodicTask;
public ManagedPeriodicTask(AbstractScheduledService periodicTask) {
this.periodicTask = periodicTask;
}
@Override
public void start() throws Exception {
periodicTask.startAsync().awaitRunning();
}
@Override
public void stop() throws Exception {
periodicTask.stopAsync().awaitTerminated();
}
}
Then on the run
method of our Application
subclass, we can do the following
package com.kountanis.dwex1;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import com.kountanis.dwex1.core.ConsoleLoggingScheduledTask;
import com.kountanis.dwex1.core.ManagedPeriodicTask;
import io.dropwizard.lifecycle.Managed;
public class DwGuavaBackgroundTasksApplication extends Application<DwGuavaBackgroundTasksConfiguration> {
public static void main(final String[] args) throws Exception {
new DwGuavaBackgroundTasksApplication().run(args);
}
@Override
public String getName() {
return "DwGuavaBackgroundTasks";
}
@Override
public void initialize(final Bootstrap<DwGuavaBackgroundTasksConfiguration> bootstrap) {
// TODO: application initialization
}
@Override
public void run(final DwGuavaBackgroundTasksConfiguration configuration,
final Environment environment) {
final ConsoleLoggingScheduledTask periodicTask = new ConsoleLoggingScheduledTask();
final Managed managedImplementer = new ManagedPeriodicTask(periodicTask);
environment.lifecycle().manage(managedImplementer);
}
}
So, there you have it! A simple way to create background (semi) periodic tasks that are managed (started and stopped) by dropwizard, for usages such as gossip protocols, consensus or asynchronous tasks like emailing and logging.