Thats right! Motherfuck this service.

Deep hidden in the javadoc of this magnificent class is this gem “If any execution of the task encounters an exception, subsequent executions are suppressed.”. In other words, if your runnable task has any fuckups, your task will no longer be run. What sucks about this, is there is no clear indication that there was a fuckup in the task. No warning, just silenty the task gets canceled leading you to say: “Dude! where my task!?”

Lets use this example:

import java.util.concurrent.Executors;

public class BadAssTask implements Runnable {

	@Override
	public void run() {
		System.out.println("Sleeping ...");
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Throwing ... ");
		throw new RuntimeException("bad ass!");
	}

	public static void main(String[] args) {
		Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new BadAssTask(), 1, 1, TimeUnit.SECONDS);
	}

}

And now comment in lines 14 & 15 and notice that it only runs once and gives no indication that the executor stopped running your task.

Ever wonder why your shit was not running… well, now you know.

But there are 2 ways to solve this:

1. try/catch that fucker!
Thats right. Put a try big ass try/catch around your entire runnable and deal with any errors. You should be doing this anyways!

2. Extened the implenentation of the ScheduledExecutorService
Thats right. Extend that fucker. Extend it to wrap all given runnables with your own runnable that has a try catch around the run method. And then log that shit in case of errors. And finally, rethrow that bitch so that existing bahavior is preserved. This is the more generic solution. Here is the code for such an Executor:

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Fuck that East Coast shit!
 *
 * @author srasul
 *
 */
public class WestCoastScheduledExecutor extends ScheduledThreadPoolExecutor {

	public WestCoastScheduledExecutor(int corePoolSize) {
		super(corePoolSize);
	}

	@Override
	public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
		return super.scheduleAtFixedRate(wrapRunnable(command), initialDelay, period, unit);
	}

	@Override
	public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
		return super.scheduleWithFixedDelay(wrapRunnable(command), initialDelay, delay, unit);
	}

	private Runnable wrapRunnable(Runnable command) {
		return new LogOnExceptionRunnable(command);
	}

	private class LogOnExceptionRunnable implements Runnable {
		private Runnable theRunnable;

		public LogOnExceptionRunnable(Runnable theRunnable) {
			super();
			this.theRunnable = theRunnable;
		}

		@Override
		public void run() {
			try {
				theRunnable.run();
			} catch (Exception e) {
				// LOG IT HERE!!!
				System.err.println("error in executing: " + theRunnable + ". It will no longer be run!");
				e.printStackTrace();

				// and re throw it so that the Executor also gets this error so that it can do what it would
				// usually do
				throw new RuntimeException(e);
			}
		}
	}

	public static void main(String[] args) {
		new WestCoastScheduledExecutor(1).scheduleAtFixedRate(new BadAssTask(), 1, 1, TimeUnit.SECONDS);
	}
}

And using this code, you can now see the exact error that was thrown by your task causing it to no longer run.