diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php
index 05ab1722b3e4f5411bb32671bb69dd03582ecd86..99739cb4cee71461bf43d1a6f0e8143b7e8939a4 100644
--- a/apps/files/appinfo/app.php
+++ b/apps/files/appinfo/app.php
@@ -20,4 +20,4 @@ OC_Search::registerProvider('OC_Search_Provider_File');
 \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
 \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
 
-\OC_BackgroundJob_RegularTask::register('\OC\Files\Cache\BackgroundWatcher', 'checkNext');
+\OCP\BackgroundJob::addRegularTask('\OC\Files\Cache\BackgroundWatcher', 'checkNext');
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 81eaa0404b759dbef6be6590521b08b47493ef52..593e846bc03f8dea4514bd05cf32c99672e90717 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -49,7 +49,7 @@ $entry = array(
 	'name' => 'LDAP'
 );
 
-OCP\Backgroundjob::addRegularTask('OCA\user_ldap\lib\Jobs', 'updateGroups');
+OCP\Backgroundjob::registerJob('OCA\user_ldap\lib\Jobs');
 if(OCP\App::isEnabled('user_webdavauth')) {
 	OCP\Util::writeLog('user_ldap',
 		'user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour',
diff --git a/apps/user_ldap/lib/jobs.php b/apps/user_ldap/lib/jobs.php
index 094d11db3d5d55681d968f077da5573dfe78ba89..60ecc0da33df57bf473a71403f14f13ec286ce7c 100644
--- a/apps/user_ldap/lib/jobs.php
+++ b/apps/user_ldap/lib/jobs.php
@@ -23,20 +23,22 @@
 
 namespace OCA\user_ldap\lib;
 
-class Jobs {
+class Jobs extends \OC\BackgroundJob\TimedJob {
 	static private $groupsFromDB;
 
 	static private $groupBE;
 	static private $connector;
 
+	public function __construct(){
+		$this->interval = self::getRefreshInterval();
+	}
+
+	public function run($argument){
+		Jobs::updateGroups();
+	}
+
 	static public function updateGroups() {
 		\OCP\Util::writeLog('user_ldap', 'Run background job "updateGroups"', \OCP\Util::DEBUG);
-		$lastUpdate = \OCP\Config::getAppValue('user_ldap', 'bgjUpdateGroupsLastRun', 0);
-		if((time() - $lastUpdate) < self::getRefreshInterval()) {
-			\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – last run too fresh, aborting.', \OCP\Util::DEBUG);
-			//komm runter Werner die Maurer geben ein aus
-			return;
-		}
 
 		$knownGroups = array_keys(self::getKnownGroups());
 		$actualGroups = self::getGroupBE()->getGroups();
@@ -45,7 +47,6 @@ class Jobs {
 			\OCP\Util::writeLog('user_ldap',
 				'bgJ "updateGroups" – groups do not seem to be configured properly, aborting.',
 				\OCP\Util::INFO);
-			\OCP\Config::setAppValue('user_ldap', 'bgjUpdateGroupsLastRun', time());
 			return;
 		}
 
@@ -53,8 +54,6 @@ class Jobs {
 		self::handleCreatedGroups(array_diff($actualGroups, $knownGroups));
 		self::handleRemovedGroups(array_diff($knownGroups, $actualGroups));
 
-		\OCP\Config::setAppValue('user_ldap', 'bgjUpdateGroupsLastRun', time());
-
 		\OCP\Util::writeLog('user_ldap', 'bgJ "updateGroups" – Finished.', \OCP\Util::DEBUG);
 	}
 
diff --git a/cron.php b/cron.php
index 69bfed8d05672e2df1a0236a9bc212c2610b5dc1..95cedf8bf4c8852bf2f22c01b6474f9cb6267cb8 100644
--- a/cron.php
+++ b/cron.php
@@ -1,24 +1,24 @@
 <?php
 /**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*
-*/
+ * ownCloud
+ *
+ * @author Jakob Sack
+ * @copyright 2012 Jakob Sack owncloud@jakobsack.de
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 
 // Unfortunately we need this class for shutdown function
 class TemporaryCronClass {
@@ -30,17 +30,16 @@ class TemporaryCronClass {
 // We use this function to handle (unexpected) shutdowns
 function handleUnexpectedShutdown() {
 	// Delete lockfile
-	if( !TemporaryCronClass::$keeplock && file_exists( TemporaryCronClass::$lockfile )) {
-		unlink( TemporaryCronClass::$lockfile );
+	if (!TemporaryCronClass::$keeplock && file_exists(TemporaryCronClass::$lockfile)) {
+		unlink(TemporaryCronClass::$lockfile);
 	}
-	
+
 	// Say goodbye if the app did not shutdown properly
-	if( !TemporaryCronClass::$sent ) {
-		if( OC::$CLI ) {
-			echo 'Unexpected error!'.PHP_EOL;
-		}
-		else{
-			OC_JSON::error( array( 'data' => array( 'message' => 'Unexpected error!')));
+	if (!TemporaryCronClass::$sent) {
+		if (OC::$CLI) {
+			echo 'Unexpected error!' . PHP_EOL;
+		} else {
+			OC_JSON::error(array('data' => array('message' => 'Unexpected error!')));
 		}
 	}
 }
@@ -50,8 +49,8 @@ require_once 'lib/base.php';
 session_write_close();
 
 // Don't do anything if ownCloud has not been installed
-if( !OC_Config::getValue( 'installed', false )) {
-	exit( 0 );
+if (!OC_Config::getValue('installed', false)) {
+	exit(0);
 }
 
 // Handle unexpected errors
@@ -62,50 +61,54 @@ OC_Helper::cleanTmpNoClean();
 
 // Exit if background jobs are disabled!
 $appmode = OC_BackgroundJob::getExecutionType();
-if( $appmode == 'none' ) {
+if ($appmode == 'none') {
 	TemporaryCronClass::$sent = true;
-	if( OC::$CLI ) {
-		echo 'Background Jobs are disabled!'.PHP_EOL;
+	if (OC::$CLI) {
+		echo 'Background Jobs are disabled!' . PHP_EOL;
+	} else {
+		OC_JSON::error(array('data' => array('message' => 'Background jobs disabled!')));
 	}
-	else{
-		OC_JSON::error( array( 'data' => array( 'message' => 'Background jobs disabled!')));
-	}
-	exit( 1 );
+	exit(1);
 }
 
-if( OC::$CLI ) {
+if (OC::$CLI) {
 	// Create lock file first
-	TemporaryCronClass::$lockfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ).'/cron.lock';
-	
+	TemporaryCronClass::$lockfile = OC_Config::getValue("datadirectory", OC::$SERVERROOT . '/data') . '/cron.lock';
+
 	// We call ownCloud from the CLI (aka cron)
-	if( $appmode != 'cron' ) {
+	if ($appmode != 'cron') {
 		// Use cron in feature!
-		OC_BackgroundJob::setExecutionType('cron' );
+		OC_BackgroundJob::setExecutionType('cron');
 	}
 
 	// check if backgroundjobs is still running
-	if( file_exists( TemporaryCronClass::$lockfile )) {
+	if (file_exists(TemporaryCronClass::$lockfile)) {
 		TemporaryCronClass::$keeplock = true;
 		TemporaryCronClass::$sent = true;
 		echo "Another instance of cron.php is still running!";
-		exit( 1 );
+		exit(1);
 	}
 
 	// Create a lock file
-	touch( TemporaryCronClass::$lockfile );
+	touch(TemporaryCronClass::$lockfile);
 
 	// Work
-	OC_BackgroundJob_Worker::doAllSteps();
-}
-else{
+	$jobList = new \OC\BackgroundJob\JobList();
+	$jobs = $jobList->getAll();
+	foreach ($jobs as $job) {
+		$job->execute($jobList);
+	}
+} else {
 	// We call cron.php from some website
-	if( $appmode == 'cron' ) {
+	if ($appmode == 'cron') {
 		// Cron is cron :-P
-		OC_JSON::error( array( 'data' => array( 'message' => 'Backgroundjobs are using system cron!')));
-	}
-	else{
+		OC_JSON::error(array('data' => array('message' => 'Backgroundjobs are using system cron!')));
+	} else {
 		// Work and success :-)
-		OC_BackgroundJob_Worker::doNextStep();
+		$jobList = new \OC\BackgroundJob\JobList();
+		$job = $jobList->getNext();
+		$job->execute($jobList);
+		$jobList->setLastJob($job);
 		OC_JSON::success();
 	}
 }
diff --git a/db_structure.xml b/db_structure.xml
index a902374e01fa1e8287105ab117ceb861e2e06f14..933b09988f0b77b4cb25c6a5cc048a2e8b05a1e8 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -859,7 +859,7 @@
 
 	<table>
 
-		<name>*dbprefix*queuedtasks</name>
+		<name>*dbprefix*jobs</name>
 
 		<declaration>
 
@@ -874,35 +874,35 @@
 			</field>
 
 			<field>
-				<name>app</name>
+				<name>class</name>
 				<type>text</type>
 				<default></default>
 				<notnull>true</notnull>
-				<length>255</length>
+				<length>256</length>
 			</field>
 
 			<field>
-				<name>klass</name>
+				<name>argument</name>
 				<type>text</type>
 				<default></default>
 				<notnull>true</notnull>
-				<length>255</length>
+				<length>256</length>
 			</field>
 
 			<field>
-				<name>method</name>
-				<type>text</type>
+				<name>last_run</name>
+				<type>integer</type>
 				<default></default>
-				<notnull>true</notnull>
-				<length>255</length>
+				<notnull>false</notnull>
 			</field>
 
-			<field>
-				<name>parameters</name>
-				<type>text</type>
-				<notnull>true</notnull>
-				<length>255</length>
-			</field>
+			<index>
+				<name>job_class_index</name>
+				<field>
+					<name>class</name>
+					<sorting>ascending</sorting>
+				</field>
+			</index>
 
 		</declaration>
 
diff --git a/lib/backgroundjob/job.php b/lib/backgroundjob/job.php
new file mode 100644
index 0000000000000000000000000000000000000000..49fbffbd6849039476790058f8e7bd64b2cf3433
--- /dev/null
+++ b/lib/backgroundjob/job.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob;
+
+abstract class Job {
+	protected $id;
+	protected $lastRun;
+	protected $argument;
+
+	/**
+	 * @param JobList $jobList
+	 */
+	public function execute($jobList) {
+		$jobList->setLastRun($this);
+		$this->run($this->argument);
+	}
+
+	abstract protected function run($argument);
+
+	public function setId($id) {
+		$this->id = $id;
+	}
+
+	public function setLastRun($lastRun) {
+		$this->lastRun = $lastRun;
+	}
+
+	public function setArgument($argument) {
+		$this->argument = $argument;
+	}
+
+	public function getId() {
+		return $this->id;
+	}
+
+	public function getLastRun() {
+		return $this->lastRun;
+	}
+
+	public function getArgument() {
+		return $this->argument;
+	}
+}
diff --git a/lib/backgroundjob/joblist.php b/lib/backgroundjob/joblist.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc803dd9b5fb73d98e5f67cb8f45f0fe5fe967f1
--- /dev/null
+++ b/lib/backgroundjob/joblist.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed once
+ *
+ * @package OC\BackgroundJob
+ */
+class JobList {
+	/**
+	 * @param Job|string $job
+	 * @param mixed $argument
+	 */
+	public function add($job, $argument = null) {
+		if (!$this->has($job, $argument)) {
+			if ($job instanceof Job) {
+				$class = get_class($job);
+			} else {
+				$class = $job;
+			}
+			$argument = json_encode($argument);
+			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)');
+			$query->execute(array($class, $argument));
+		}
+	}
+
+	/**
+	 * @param Job|string $job
+	 * @param mixed $argument
+	 */
+	public function remove($job, $argument = null) {
+		if ($job instanceof Job) {
+			$class = get_class($job);
+		} else {
+			$class = $job;
+		}
+		if (!is_null($argument)) {
+			$argument = json_encode($argument);
+			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
+			$query->execute(array($class, $argument));
+		} else {
+			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?');
+			$query->execute(array($class));
+		}
+	}
+
+	/**
+	 * check if a job is in the list
+	 *
+	 * @param $job
+	 * @param mixed $argument
+	 * @return bool
+	 */
+	public function has($job, $argument) {
+		if ($job instanceof Job) {
+			$class = get_class($job);
+		} else {
+			$class = $job;
+		}
+		$argument = json_encode($argument);
+		$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
+		$result = $query->execute(array($class, $argument));
+		return (bool)$result->fetchRow();
+	}
+
+	/**
+	 * get all jobs in the list
+	 *
+	 * @return Job[]
+	 */
+	public function getAll() {
+		$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`');
+		$result = $query->execute();
+		$jobs = array();
+		while ($row = $result->fetchRow()) {
+			$jobs[] = $this->buildJob($row);
+		}
+		return $jobs;
+	}
+
+	/**
+	 * get the next job in the list
+	 *
+	 * @return Job
+	 */
+	public function getNext() {
+		$lastId = $this->getLastJob();
+		$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1);
+		$result = $query->execute(array($lastId));
+		if ($row = $result->fetchRow()) {
+			return $this->buildJob($row);
+		} else {
+			//begin at the start of the queue
+			$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1);
+			$result = $query->execute();
+			if ($row = $result->fetchRow()) {
+				return $this->buildJob($row);
+			} else {
+				return null; //empty job list
+			}
+		}
+	}
+
+	/**
+	 * @param int $id
+	 * @return Job
+	 */
+	public function getById($id) {
+		$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?');
+		$result = $query->execute(array($id));
+		if ($row = $result->fetchRow()) {
+			return $this->buildJob($row);
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * get the job object from a row in the db
+	 *
+	 * @param array $row
+	 * @return Job
+	 */
+	private function buildJob($row) {
+		$class = $row['class'];
+		/**
+		 * @var Job $job
+		 */
+		$job = new $class();
+		$job->setId($row['id']);
+		$job->setLastRun($row['last_run']);
+		$job->setArgument(json_decode($row['argument']));
+		return $job;
+	}
+
+	/**
+	 * set the job that was last ran
+	 *
+	 * @param Job $job
+	 */
+	public function setLastJob($job) {
+		\OC_Appconfig::setValue('backgroundjob', 'lastjob', $job->getId());
+	}
+
+	/**
+	 * get the id of the last ran job
+	 *
+	 * @return int
+	 */
+	public function getLastJob() {
+		return \OC_Appconfig::getValue('backgroundjob', 'lastjob', 0);
+	}
+
+	/**
+	 * set the lastRun of $job to now
+	 *
+	 * @param Job $job
+	 */
+	public function setLastRun($job) {
+		$query = \OC_DB::prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?');
+		$query->execute(array(time(), $job->getId()));
+	}
+}
diff --git a/lib/backgroundjob/legacy/queuedjob.php b/lib/backgroundjob/legacy/queuedjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..2bc001103b8607008d1dbb27a6466555a51880cb
--- /dev/null
+++ b/lib/backgroundjob/legacy/queuedjob.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob\Legacy;
+
+class QueuedJob extends \OC\BackgroundJob\QueuedJob {
+	public function run($argument) {
+		$class = $argument['klass'];
+		$method = $argument['method'];
+		$parameters = $argument['parameters'];
+		call_user_func(array($class, $method), $parameters);
+	}
+}
diff --git a/lib/backgroundjob/legacy/regularjob.php b/lib/backgroundjob/legacy/regularjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..d4cfa348ceace0ecd286df18d6d2a2f51bafa592
--- /dev/null
+++ b/lib/backgroundjob/legacy/regularjob.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob\Legacy;
+
+class RegularJob extends \OC\BackgroundJob\Job {
+	public function run($argument) {
+		call_user_func($argument);
+	}
+}
diff --git a/lib/backgroundjob/queuedjob.php b/lib/backgroundjob/queuedjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..1714182820df3d8ba6c8e32cf5b72e4ae90eb4ae
--- /dev/null
+++ b/lib/backgroundjob/queuedjob.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed once
+ *
+ * @package OC\BackgroundJob
+ */
+abstract class QueuedJob extends Job {
+	/**
+	 * run the job, then remove it from the joblist
+	 *
+	 * @param JobList $jobList
+	 */
+	public function execute($jobList) {
+		$jobList->remove($this);
+		$this->run($this->argument);
+	}
+}
diff --git a/lib/backgroundjob/queuedtask.php b/lib/backgroundjob/queuedtask.php
deleted file mode 100644
index b2ce6f39ed8ed365346e0508f400b592baf23837..0000000000000000000000000000000000000000
--- a/lib/backgroundjob/queuedtask.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
-/**
- * This class manages our queued tasks.
- */
-class OC_BackgroundJob_QueuedTask{
-	/**
-	 * @brief Gets one queued task
-	 * @param $id ID of the task
-	 * @return associative array
-	 */
-	public static function find( $id ) {
-		$stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks` WHERE `id` = ?' );
-		$result = $stmt->execute(array($id));
-		return $result->fetchRow();
-	}
-
-	/**
-	 * @brief Gets all queued tasks
-	 * @return array with associative arrays
-	 */
-	public static function all() {
-		// Array for objects
-		$return = array();
-
-		// Get Data
-		$stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks`' );
-		$result = $stmt->execute(array());
-		while( $row = $result->fetchRow()) {
-			$return[] = $row;
-		}
-
-		return $return;
-	}
-
-	/**
-	 * @brief Gets all queued tasks of a specific app
-	 * @param $app app name
-	 * @return array with associative arrays
-	 */
-	public static function whereAppIs( $app ) {
-		// Array for objects
-		$return = array();
-
-		// Get Data
-		$stmt = OC_DB::prepare( 'SELECT * FROM `*PREFIX*queuedtasks` WHERE `app` = ?' );
-		$result = $stmt->execute(array($app));
-		while( $row = $result->fetchRow()) {
-			$return[] = $row;
-		}
-
-		// Und weg damit
-		return $return;
-	}
-
-	/**
-	 * @brief queues a task
-	 * @param $app app name
-	 * @param $klass class name
-	 * @param $method method name
-	 * @param $parameters all useful data as text
-	 * @return id of task
-	 */
-	public static function add( $app, $klass, $method, $parameters ) {
-		$stmt = OC_DB::prepare( 'INSERT INTO `*PREFIX*queuedtasks` (`app`, `klass`, `method`, `parameters`)'
-			.' VALUES(?,?,?,?)' );
-		$result = $stmt->execute(array($app, $klass, $method, $parameters ));
-
-		return OC_DB::insertid();
-	}
-
-	/**
-	 * @brief deletes a queued task
-	 * @param $id id of task
-	 * @return true/false
-	 *
-	 * Deletes a report
-	 */
-	public static function delete( $id ) {
-		$stmt = OC_DB::prepare( 'DELETE FROM `*PREFIX*queuedtasks` WHERE `id` = ?' );
-		$result = $stmt->execute(array($id));
-
-		return true;
-	}
-}
diff --git a/lib/backgroundjob/regulartask.php b/lib/backgroundjob/regulartask.php
deleted file mode 100644
index 9976872ee13f75f4005fb7bd8fc5a813c2f4715d..0000000000000000000000000000000000000000
--- a/lib/backgroundjob/regulartask.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
-/**
- * This class manages the regular tasks.
- */
-class OC_BackgroundJob_RegularTask{
-	static private $registered = array();
-
-	/**
-	 * @brief creates a regular task
-	 * @param $klass class name
-	 * @param $method method name
-	 * @return true
-	 */
-	static public function register( $klass, $method ) {
-		// Create the data structure
-		self::$registered["$klass-$method"] = array( $klass, $method );
-
-		// No chance for failure ;-)
-		return true;
-	}
-
-	/**
-	 * @brief gets all regular tasks
-	 * @return associative array
-	 *
-	 * key is string "$klass-$method", value is array( $klass, $method )
-	 */
-	static public function all() {
-		return self::$registered;
-	}
-}
diff --git a/lib/backgroundjob/timedjob.php b/lib/backgroundjob/timedjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae9f33505abe169a5d04472e6052476831d11d2b
--- /dev/null
+++ b/lib/backgroundjob/timedjob.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\BackgroundJob;
+
+/**
+ * Class QueuedJob
+ *
+ * create a background job that is to be executed at an interval
+ *
+ * @package OC\BackgroundJob
+ */
+abstract class TimedJob extends Job {
+	protected $interval = 0;
+
+	/**
+	 * set the interval for the job
+	 *
+	 * @param int $interval
+	 */
+	public function setInterval($interval) {
+		$this->interval = $interval;
+	}
+
+	/**
+	 * run the job if
+	 *
+	 * @param JobList $jobList
+	 */
+	public function execute($jobList) {
+		if ((time() - $this->lastRun) > $this->interval) {
+			$jobList->setLastRun($this);
+			$this->run($this->argument);
+		}
+	}
+}
diff --git a/lib/backgroundjob/worker.php b/lib/backgroundjob/worker.php
deleted file mode 100644
index e966ac9647c0fc90601bc58915c2e02ce0906d11..0000000000000000000000000000000000000000
--- a/lib/backgroundjob/worker.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
-/**
- * This class does the dirty work.
- *
- * TODO: locking in doAllSteps
- */
-class OC_BackgroundJob_Worker{
-	/**
-	 * @brief executes all tasks
-	 * @return boolean
-	 *
-	 * This method executes all regular tasks and then all queued tasks.
-	 * This method should be called by cli scripts that do not let the user
-	 * wait.
-	 */
-	public static function doAllSteps() {
-		// Do our regular work
-		$lasttask = OC_Appconfig::getValue( 'core', 'backgroundjobs_task', '' );
-
-		$regular_tasks = OC_BackgroundJob_RegularTask::all();
-		ksort( $regular_tasks );
-		foreach( $regular_tasks as $key => $value ) {
-			if( strcmp( $key, $lasttask ) > 0 ) {
-				// Set "restart here" config value
-				OC_Appconfig::setValue( 'core', 'backgroundjobs_task', $key );
-				call_user_func( $value );
-			}
-		}
-		// Reset "start here" config value
-		OC_Appconfig::setValue( 'core', 'backgroundjobs_task', '' );
-
-		// Do our queued tasks
-		$queued_tasks = OC_BackgroundJob_QueuedTask::all();
-		foreach( $queued_tasks as $task ) {
-			OC_BackgroundJob_QueuedTask::delete( $task['id'] );
-			call_user_func( array( $task['klass'], $task['method'] ), $task['parameters'] );
-		}
-
-		return true;
-	}
-
-	/**
-	 * @brief does a single task
-	 * @return boolean
-	 *
-	 * This method executes one task. It saves the last state and continues
-	 * with the next step. This method should be used by webcron and ajax
-	 * services.
-	 */
-	public static function doNextStep() {
-		$laststep = OC_Appconfig::getValue( 'core', 'backgroundjobs_step', 'regular_tasks' );
-
-		if( $laststep == 'regular_tasks' ) {
-			// get last app
-			$lasttask = OC_Appconfig::getValue( 'core', 'backgroundjobs_task', '' );
-
-			// What's the next step?
-			$regular_tasks = OC_BackgroundJob_RegularTask::all();
-			ksort( $regular_tasks );
-			$done = false;
-
-			// search for next background job
-			foreach( $regular_tasks as $key => $value ) {
-				if( strcmp( $key, $lasttask ) > 0 ) {
-					OC_Appconfig::setValue( 'core', 'backgroundjobs_task', $key );
-					$done = true;
-					call_user_func( $value );
-					break;
-				}
-			}
-
-			if( $done == false ) {
-				// Next time load queued tasks
-				OC_Appconfig::setValue( 'core', 'backgroundjobs_step', 'queued_tasks' );
-			}
-		}
-		else{
-			$tasks = OC_BackgroundJob_QueuedTask::all();
-			if( count( $tasks )) {
-				$task = $tasks[0];
-				// delete job before we execute it. This prevents endless loops
-				// of failing jobs.
-				OC_BackgroundJob_QueuedTask::delete($task['id']);
-
-				// execute job
-				call_user_func( array( $task['klass'], $task['method'] ), $task['parameters'] );
-			}
-			else{
-				// Next time load queued tasks
-				OC_Appconfig::setValue( 'core', 'backgroundjobs_step', 'regular_tasks' );
-				OC_Appconfig::setValue( 'core', 'backgroundjobs_task', '' );
-			}
-		}
-
-		return true;
-	}
-}
diff --git a/lib/base.php b/lib/base.php
index 9d1d4b5e0587b20b4dd7eed6cba312cbc5422147..d2a3d90f8251e9bd01b2bffeb84f5b5ddac2ae85 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -537,9 +537,15 @@ class OC {
 	 * register hooks for the cache
 	 */
 	public static function registerCacheHooks() {
-		// register cache cleanup jobs
-		OC_BackgroundJob_RegularTask::register('OC_Cache_FileGlobal', 'gc');
-		OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
+		if (OC_Config::getValue('installed', false)) { //don't try to do this before we are properly setup
+			// register cache cleanup jobs
+			try { //if this is executed before the upgrade to the new backgroundjob system is completed it will throw an exception
+				\OCP\BackgroundJob::registerJob('OC_Cache_FileGlobalGC');
+			} catch (Exception $e) {
+
+			}
+			OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
+		}
 	}
 
 	/**
diff --git a/lib/cache/fileglobalgc.php b/lib/cache/fileglobalgc.php
new file mode 100644
index 0000000000000000000000000000000000000000..a29c31f9063087a49dd9d0d3c498d1e1fe23e68d
--- /dev/null
+++ b/lib/cache/fileglobalgc.php
@@ -0,0 +1,8 @@
+<?php
+
+
+class OC_Cache_FileGlobalGC extends \OC\BackgroundJob\Job{
+	public function run($argument){
+		OC_Cache_FileGlobal::gc();
+	}
+}
diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php
index 02cce001b481a29109c6d68e826414b003f011da..d3fddf8c421ba73f19e0d172acef4e6cf15ff669 100644
--- a/lib/files/filesystem.php
+++ b/lib/files/filesystem.php
@@ -152,6 +152,9 @@ class Filesystem {
 	 * @return string
 	 */
 	static public function getMountPoint($path) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		$mount = self::$mounts->find($path);
 		if ($mount) {
 			return $mount->getMountPoint();
@@ -167,6 +170,9 @@ class Filesystem {
 	 * @return string[]
 	 */
 	static public function getMountPoints($path) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		$result = array();
 		$mounts = self::$mounts->findIn($path);
 		foreach ($mounts as $mount) {
@@ -182,6 +188,9 @@ class Filesystem {
 	 * @return \OC\Files\Storage\Storage
 	 */
 	public static function getStorage($mountPoint) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		$mount = self::$mounts->find($mountPoint);
 		return $mount->getStorage();
 	}
@@ -191,6 +200,9 @@ class Filesystem {
 	 * @return Mount\Mount[]
 	 */
 	public static function getMountByStorageId($id) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		return self::$mounts->findByStorageId($id);
 	}
 
@@ -199,6 +211,9 @@ class Filesystem {
 	 * @return Mount\Mount[]
 	 */
 	public static function getMountByNumericId($id) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		return self::$mounts->findByNumericId($id);
 	}
 
@@ -209,6 +224,9 @@ class Filesystem {
 	 * @return array consisting of the storage and the internal path
 	 */
 	static public function resolvePath($path) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		$mount = self::$mounts->find($path);
 		if ($mount) {
 			return array($mount->getStorage(), $mount->getInternalPath($path));
@@ -223,7 +241,7 @@ class Filesystem {
 		}
 		self::$defaultInstance = new View($root);
 
-		if(!self::$mounts) {
+		if (!self::$mounts) {
 			self::$mounts = new Mount\Manager();
 		}
 
@@ -235,8 +253,8 @@ class Filesystem {
 		return true;
 	}
 
-	static public function initMounts(){
-		if(!self::$mounts) {
+	static public function initMounts() {
+		if (!self::$mounts) {
 			self::$mounts = new Mount\Manager();
 		}
 	}
@@ -359,7 +377,9 @@ class Filesystem {
 	 * clear all mounts and storage backends
 	 */
 	public static function clearMounts() {
-		self::$mounts->clear();
+		if (self::$mounts) {
+			self::$mounts->clear();
+		}
 	}
 
 	/**
@@ -370,6 +390,9 @@ class Filesystem {
 	 * @param string $mountpoint
 	 */
 	static public function mount($class, $arguments, $mountpoint) {
+		if (!self::$mounts) {
+			\OC_Util::setupFS();
+		}
 		$mount = new Mount\Mount($class, $mountpoint, $arguments);
 		self::$mounts->addMount($mount);
 	}
diff --git a/lib/public/backgroundjob.php b/lib/public/backgroundjob.php
index 601046fe691dcf9146371699d060bb03f436b485..cc076a3a845ad2944721cc8346c686434475dc9c 100644
--- a/lib/public/backgroundjob.php
+++ b/lib/public/backgroundjob.php
@@ -1,49 +1,46 @@
 <?php
 /**
-* ownCloud
-*
-* @author Jakob Sack
-* @copyright 2012 Jakob Sack owncloud@jakobsack.de
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
-*
-*/
+ * ownCloud
+ *
+ * @author Jakob Sack
+ * @copyright 2012 Jakob Sack owncloud@jakobsack.de
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 
 /**
- * Public interface of ownCloud forbackground jobs.
+ * Public interface of ownCloud for background jobs.
  */
 
 // use OCP namespace for all classes that are considered public.
 // This means that they should be used by apps instead of the internal ownCloud classes
 namespace OCP;
 
+use \OC\BackgroundJob\JobList;
+
 /**
- * This class provides functions to manage backgroundjobs in ownCloud
- *
- * There are two kind of background jobs in ownCloud: regular tasks and
- * queued tasks.
+ * This class provides functions to register backgroundjobs in ownCloud
  *
- * Regular tasks have to be registered in appinfo.php and
- * will run on a regular base. Fetching news could be a task that should run
- * frequently.
+ * To create a new backgroundjob create a new class that inharits from either \OC\BackgroundJob\Job,
+ * \OC\BackgroundJob\QueuedJob or \OC\BackgroundJob\TimedJob and register it using
+ * \OCP\BackgroundJob->registerJob($job, $argument), $argument will be passed to the run() function
+ * of the job when the job is executed.
  *
- * Queued tasks have to be registered each time you want to execute them.
- * An example of the queued task would be the creation of the thumbnail. As
- * soon as the user uploads a picture the gallery app registers the queued
- * task "create thumbnail" and saves the path in the parameter instead of doing
- * the work right away. This makes the app more responsive. As soon as the task
- * is done it will be deleted from the list.
+ * A regular Job will be executed every time cron.php is run, a QueuedJob will only run once and a TimedJob
+ * will only run at a specific interval which is to be specified in the constructor of the job by calling
+ * $this->setInterval($interval) with $interval in seconds.
  */
 class BackgroundJob {
 	/**
@@ -59,82 +56,136 @@ class BackgroundJob {
 
 	/**
 	 * @brief sets the background jobs execution type
-	 * @param $type execution type
+	 * @param string $type execution type
 	 * @return boolean
 	 *
 	 * This method sets the execution type of the background jobs. Possible types
 	 * are "none", "ajax", "webcron", "cron"
 	 */
-	public static function setExecutionType( $type ) {
-		return \OC_BackgroundJob::setExecutionType( $type );
+	public static function setExecutionType($type) {
+		return \OC_BackgroundJob::setExecutionType($type);
+	}
+
+	/**
+	 * @param \OC\BackgroundJob\Job|string $job
+	 * @param mixed $argument
+	 */
+	public static function registerJob($job, $argument = null) {
+		$jobList = new JobList();
+		$jobList->add($job, $argument);
 	}
 
 	/**
+	 * @deprecated
 	 * @brief creates a regular task
-	 * @param $klass class name
-	 * @param $method method name
+	 * @param string $klass class name
+	 * @param string $method method name
 	 * @return true
 	 */
-	public static function addRegularTask( $klass, $method ) {
-		return \OC_BackgroundJob_RegularTask::register( $klass, $method );
+	public static function addRegularTask($klass, $method) {
+		self::registerJob('OC\BackgroundJob\Legacy\RegularJob', array($klass, $method));
+		return true;
 	}
 
 	/**
+	 * @deprecated
 	 * @brief gets all regular tasks
 	 * @return associative array
 	 *
 	 * key is string "$klass-$method", value is array( $klass, $method )
 	 */
 	static public function allRegularTasks() {
-		return \OC_BackgroundJob_RegularTask::all();
+		$jobList = new JobList();
+		$allJobs = $jobList->getAll();
+		$regularJobs = array();
+		foreach ($allJobs as $job) {
+			if ($job instanceof RegularLegacyJob) {
+				$key = implode('-', $job->getArgument());
+				$regularJobs[$key] = $job->getArgument();
+			}
+		}
+		return $regularJobs;
 	}
 
 	/**
+	 * @deprecated
 	 * @brief Gets one queued task
-	 * @param $id ID of the task
+	 * @param int $id ID of the task
 	 * @return associative array
 	 */
-	public static function findQueuedTask( $id ) {
-		return \OC_BackgroundJob_QueuedTask::find( $id );
+	public static function findQueuedTask($id) {
+		$jobList = new JobList();
+		return $jobList->getById($id);
 	}
 
 	/**
+	 * @deprecated
 	 * @brief Gets all queued tasks
 	 * @return array with associative arrays
 	 */
 	public static function allQueuedTasks() {
-		return \OC_BackgroundJob_QueuedTask::all();
+		$jobList = new JobList();
+		$allJobs = $jobList->getAll();
+		$queuedJobs = array();
+		foreach ($allJobs as $job) {
+			if ($job instanceof QueuedLegacyJob) {
+				$queuedJob = $job->getArgument();
+				$queuedJob['id'] = $job->getId();
+				$queuedJobs[] = $queuedJob;
+			}
+		}
+		return $queuedJobs;
 	}
 
 	/**
+	 * @deprecated
 	 * @brief Gets all queued tasks of a specific app
-	 * @param $app app name
+	 * @param string $app app name
 	 * @return array with associative arrays
 	 */
-	public static function queuedTaskWhereAppIs( $app ) {
-		return \OC_BackgroundJob_QueuedTask::whereAppIs( $app );
+	public static function queuedTaskWhereAppIs($app) {
+		$jobList = new JobList();
+		$allJobs = $jobList->getAll();
+		$queuedJobs = array();
+		foreach ($allJobs as $job) {
+			if ($job instanceof QueuedLegacyJob) {
+				$queuedJob = $job->getArgument();
+				$queuedJob['id'] = $job->getId();
+				if ($queuedJob['app'] === $app) {
+					$queuedJobs[] = $queuedJob;
+				}
+			}
+		}
+		return $queuedJobs;
 	}
 
 	/**
+	 * @deprecated
 	 * @brief queues a task
-	 * @param $app app name
-	 * @param $klass class name
-	 * @param $method method name
-	 * @param $parameters all useful data as text
-	 * @return id of task
+	 * @param string $app app name
+	 * @param string $class class name
+	 * @param string $method method name
+	 * @param string $parameters all useful data as text
+	 * @return int id of task
 	 */
-	public static function addQueuedTask( $app, $klass, $method, $parameters ) {
-		return \OC_BackgroundJob_QueuedTask::add( $app, $klass, $method, $parameters );
+	public static function addQueuedTask($app, $class, $method, $parameters) {
+		self::registerJob('OC\BackgroundJob\Legacy\QueuedJob', array('app' => $app, 'klass' => $class, 'method' => $method, 'parameters' => $parameters));
+		return true;
 	}
 
 	/**
+	 * @deprecated
 	 * @brief deletes a queued task
-	 * @param $id id of task
-	 * @return true/false
+	 * @param int $id id of task
+	 * @return bool
 	 *
 	 * Deletes a report
 	 */
-	public static function deleteQueuedTask( $id ) {
-		return \OC_BackgroundJob_QueuedTask::delete( $id );
+	public static function deleteQueuedTask($id) {
+		$jobList = new JobList();
+		$job = $jobList->getById($id);
+		if ($job) {
+			$jobList->remove($job);
+		}
 	}
 }
diff --git a/lib/util.php b/lib/util.php
index 035815c057f61cf5df4ecbd7f366ac0e03a03aa9..95af22ed0eedfa9481ae2f63b7caa997ba32a307 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -80,7 +80,7 @@ class OC_Util {
 	public static function getVersion() {
 		// hint: We only can count up. Reset minor/patchlevel when
 		// updating major/minor version number.
-		return array(5, 80, 04);
+		return array(5, 80, 05);
 	}
 
 	/**
diff --git a/tests/lib/backgroundjob/dummyjoblist.php b/tests/lib/backgroundjob/dummyjoblist.php
new file mode 100644
index 0000000000000000000000000000000000000000..d91d6b344b5f05d2c8410675c0d15970b299a064
--- /dev/null
+++ b/tests/lib/backgroundjob/dummyjoblist.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\BackgroundJob;
+
+class JobRun extends \Exception {
+}
+
+/**
+ * Class DummyJobList
+ *
+ * in memory job list for testing purposes
+ */
+class DummyJobList extends \OC\BackgroundJob\JobList {
+	/**
+	 * @var \OC\BackgroundJob\Job[]
+	 */
+	private $jobs = array();
+
+	private $last = 0;
+
+	/**
+	 * @param \OC\BackgroundJob\Job|string $job
+	 * @param mixed $argument
+	 */
+	public function add($job, $argument = null) {
+		$job->setArgument($argument);
+		if (!$this->has($job, null)) {
+			$this->jobs[] = $job;
+		}
+	}
+
+	/**
+	 * @param \OC\BackgroundJob\Job|string $job
+	 * @param mixed $argument
+	 */
+	public function remove($job, $argument = null) {
+		$index = array_search($job, $this->jobs);
+		if ($index !== false) {
+			unset($this->jobs[$index]);
+		}
+	}
+
+	/**
+	 * check if a job is in the list
+	 *
+	 * @param $job
+	 * @param mixed $argument
+	 * @return bool
+	 */
+	public function has($job, $argument) {
+		return array_search($job, $this->jobs) !== false;
+	}
+
+	/**
+	 * get all jobs in the list
+	 *
+	 * @return \OC\BackgroundJob\Job[]
+	 */
+	public function getAll() {
+		return $this->jobs;
+	}
+
+	/**
+	 * get the next job in the list
+	 *
+	 * @return \OC\BackgroundJob\Job
+	 */
+	public function getNext() {
+		if (count($this->jobs) > 0) {
+			if ($this->last < (count($this->jobs) - 1)) {
+				$i = $this->last + 1;
+			} else {
+				$i = 0;
+			}
+			return $this->jobs[$i];
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * set the job that was last ran
+	 *
+	 * @param \OC\BackgroundJob\Job $job
+	 */
+	public function setLastJob($job) {
+		$i = array_search($job, $this->jobs);
+		if ($i !== false) {
+			$this->last = $i;
+		} else {
+			$this->last = 0;
+		}
+	}
+
+	/**
+	 * @param int $id
+	 * @return Job
+	 */
+	public function getById($id) {
+		foreach ($this->jobs as $job) {
+			if ($job->getId() === $id) {
+				return $job;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * get the id of the last ran job
+	 *
+	 * @return int
+	 */
+	public function getLastJob() {
+		return $this->last;
+	}
+
+	/**
+	 * set the lastRun of $job to now
+	 *
+	 * @param \OC\BackgroundJob\Job $job
+	 */
+	public function setLastRun($job) {
+		$job->setLastRun(time());
+	}
+}
diff --git a/tests/lib/backgroundjob/queuedjob.php b/tests/lib/backgroundjob/queuedjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d373473cd7ae1b7e5c0469363e7fbe519fa042c
--- /dev/null
+++ b/tests/lib/backgroundjob/queuedjob.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\BackgroundJob;
+
+class TestQueuedJob extends \OC\BackgroundJob\QueuedJob {
+	public function run($argument) {
+		throw new JobRun(); //throw an exception so we can detect if this function is called
+	}
+}
+
+class QueuedJob extends \PHPUnit_Framework_TestCase {
+	/**
+	 * @var DummyJobList $jobList
+	 */
+	private $jobList;
+	/**
+	 * @var \OC\BackgroundJob\TimedJob $job
+	 */
+	private $job;
+
+	public function setup() {
+		$this->jobList = new DummyJobList();
+		$this->job = new TestQueuedJob();
+		$this->jobList->add($this->job);
+	}
+
+	public function testJobShouldBeRemoved() {
+		try {
+			$this->assertTrue($this->jobList->has($this->job, null));
+			$this->job->execute($this->jobList);
+			$this->fail("job should have been run");
+		} catch (JobRun $e) {
+			$this->assertFalse($this->jobList->has($this->job, null));
+		}
+	}
+}
diff --git a/tests/lib/backgroundjob/timedjob.php b/tests/lib/backgroundjob/timedjob.php
new file mode 100644
index 0000000000000000000000000000000000000000..0af933afef873adea45a7e3bfb84557ccac433fa
--- /dev/null
+++ b/tests/lib/backgroundjob/timedjob.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\BackgroundJob;
+
+class TestTimedJob extends \OC\BackgroundJob\TimedJob {
+	public function __construct() {
+		$this->setInterval(10);
+	}
+
+	public function run($argument) {
+		throw new JobRun(); //throw an exception so we can detect if this function is called
+	}
+}
+
+class TimedJob extends \PHPUnit_Framework_TestCase {
+	/**
+	 * @var DummyJobList $jobList
+	 */
+	private $jobList;
+	/**
+	 * @var \OC\BackgroundJob\TimedJob $job
+	 */
+	private $job;
+
+	public function setup() {
+		$this->jobList = new DummyJobList();
+		$this->job = new TestTimedJob();
+		$this->jobList->add($this->job);
+	}
+
+	public function testShouldRunAfterInterval() {
+		$this->job->setLastRun(time() - 12);
+		try {
+			$this->job->execute($this->jobList);
+			$this->fail("job should have run");
+		} catch (JobRun $e) {
+		}
+	}
+
+	public function testShouldNotRunWithinInterval() {
+		$this->job->setLastRun(time() - 5);
+		try {
+			$this->job->execute($this->jobList);
+		} catch (JobRun $e) {
+			$this->fail("job should not have run");
+		}
+	}
+
+	public function testShouldNotTwice() {
+		$this->job->setLastRun(time() - 15);
+		try {
+			$this->job->execute($this->jobList);
+			$this->fail("job should have run the first time");
+		} catch (JobRun $e) {
+			try {
+				$this->job->execute($this->jobList);
+			} catch (JobRun $e) {
+				$this->fail("job should not have run the second time");
+			}
+		}
+	}
+}