diff --git a/setup.cfg b/setup.cfg
index 758024dff..c96636842 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -27,6 +27,13 @@ setup-hooks =
 packages =
     taskflow
 
+[entry_points]
+taskflow.persistence =
+    memory = taskflow.persistence.backends.impl_memory:MemoryBackend
+    mysql = taskflow.persistence.backends.impl_sqlalchemy:SQLAlchemyBackend
+    postgresql = taskflow.persistence.backends.impl_sqlalchemy:SQLAlchemyBackend
+    sqlite = taskflow.persistence.backends.impl_sqlalchemy:SQLAlchemyBackend
+
 [nosetests]
 cover-erase = true
 verbosity = 2
diff --git a/taskflow/engines/action_engine/engine.py b/taskflow/engines/action_engine/engine.py
index 038373b1f..92ceb5a8c 100644
--- a/taskflow/engines/action_engine/engine.py
+++ b/taskflow/engines/action_engine/engine.py
@@ -27,6 +27,8 @@ from taskflow.engines.action_engine import task_action
 from taskflow.patterns import linear_flow as lf
 from taskflow.patterns import unordered_flow as uf
 
+from taskflow.persistence import utils as p_utils
+
 from taskflow import decorators
 from taskflow import exceptions as exc
 from taskflow import states
@@ -140,9 +142,13 @@ class SingleThreadedTranslator(Translator):
 class SingleThreadedActionEngine(ActionEngine):
     translator_cls = SingleThreadedTranslator
 
-    def __init__(self, flow, flow_detail=None):
+    def __init__(self, flow, flow_detail=None, book=None, backend=None):
+        if flow_detail is None:
+            flow_detail = p_utils.create_flow_detail(flow,
+                                                     book=book,
+                                                     backend=backend)
         ActionEngine.__init__(self, flow,
-                              storage=t_storage.Storage(flow_detail))
+                              storage=t_storage.Storage(flow_detail, backend))
 
 
 class MultiThreadedTranslator(Translator):
@@ -168,9 +174,15 @@ class MultiThreadedTranslator(Translator):
 class MultiThreadedActionEngine(ActionEngine):
     translator_cls = MultiThreadedTranslator
 
-    def __init__(self, flow, flow_detail=None, thread_pool=None):
+    def __init__(self, flow, flow_detail=None, book=None, backend=None,
+                 thread_pool=None):
+        if flow_detail is None:
+            flow_detail = p_utils.create_flow_detail(flow,
+                                                     book=book,
+                                                     backend=backend)
         ActionEngine.__init__(self, flow,
-                              storage=t_storage.ThreadSafeStorage(flow_detail))
+                              storage=t_storage.ThreadSafeStorage(flow_detail,
+                                                                  backend))
         if thread_pool:
             self._thread_pool = thread_pool
             self._owns_thread_pool = False
diff --git a/taskflow/persistence/__init__.py b/taskflow/persistence/__init__.py
index 3a554a5f7..fbe1837c3 100644
--- a/taskflow/persistence/__init__.py
+++ b/taskflow/persistence/__init__.py
@@ -2,7 +2,7 @@
 
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
+#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
diff --git a/taskflow/persistence/backends/__init__.py b/taskflow/persistence/backends/__init__.py
index 3a554a5f7..18ba20988 100644
--- a/taskflow/persistence/backends/__init__.py
+++ b/taskflow/persistence/backends/__init__.py
@@ -2,7 +2,7 @@
 
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
+#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -15,3 +15,27 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+
+import logging
+import urlparse
+
+from stevedore import driver
+
+from taskflow import exceptions as exc
+
+# NOTE(harlowja): this is the entrypoint namespace, not the module namespace.
+BACKEND_NAMESPACE = 'taskflow.persistence'
+
+LOG = logging.getLogger(__name__)
+
+
+def fetch(conf, namespace=BACKEND_NAMESPACE):
+    backend_name = urlparse.urlparse(conf['connection']).scheme
+    LOG.debug('Looking for %r backend driver in %r', backend_name, namespace)
+    try:
+        mgr = driver.DriverManager(namespace, backend_name,
+                                   invoke_on_load=True,
+                                   invoke_kwds={'conf': conf})
+        return mgr.driver
+    except RuntimeError as e:
+        raise exc.NotFound("Could not find backend %s: %s" % (backend_name, e))
diff --git a/taskflow/persistence/backends/api.py b/taskflow/persistence/backends/api.py
deleted file mode 100644
index 8845e0227..000000000
--- a/taskflow/persistence/backends/api.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import threading
-
-from taskflow import exceptions as exc
-from taskflow.openstack.common import importutils
-
-
-_BACKEND_MAPPING = {
-    'memory': 'taskflow.persistence.backends.memory.api',
-    'sqlalchemy': 'taskflow.persistence.backends.sqlalchemy.api',
-    # TODO(harlowja): we likely need to allow more customization here so that
-    # its easier for a user of this library to alter the impl to there own
-    # choicing, aka, cinder has its own DB, or heat may want to write this
-    # information into swift, we need a way to accomodate that.
-}
-_BACKEND_MAPPING_LOCK = threading.RLock()
-_BACKENDS = {}
-_BACKEND_LOCK = threading.RLock()
-
-
-def register(backend, module):
-    """Register a new (or override an old) backend type.
-
-    Instead of being restricted to the existing types that are pre-registered
-    in taskflow it is useful to allow others to either override those types
-    or add new ones (since all backend types can not be predicted ahead of
-    time).
-    """
-    with _BACKEND_MAPPING_LOCK:
-        _BACKEND_MAPPING[backend] = str(module)
-
-
-def fetch(backend):
-    """Fetch a backend impl. for a given backend type."""
-    with _BACKEND_MAPPING_LOCK:
-        if backend not in _BACKEND_MAPPING:
-            raise exc.NotFound("Unknown backend %s requested" % (backend))
-        mod = _BACKEND_MAPPING.get(backend, backend)
-    with _BACKEND_LOCK:
-        if mod in _BACKENDS:
-            return _BACKENDS[mod]
-        backend_mod = importutils.import_module(mod)
-        backend_impl = backend_mod.get_backend()
-        _BACKENDS[mod] = backend_impl
-        return backend_impl
diff --git a/taskflow/persistence/backends/base.py b/taskflow/persistence/backends/base.py
new file mode 100644
index 000000000..070d73719
--- /dev/null
+++ b/taskflow/persistence/backends/base.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import abc
+
+
+class Backend(object):
+    """Base class for persistence backends."""
+
+    __metaclass__ = abc.ABCMeta
+
+    def __init__(self, conf):
+        self._conf = conf
+
+    @abc.abstractmethod
+    def get_connection(self):
+        """Return a Connection instance based on the configuration settings."""
+        pass
+
+    @abc.abstractmethod
+    def close(self):
+        """Closes any resources this backend has open."""
+        pass
+
+
+class Connection(object):
+    """Base class for backend connections."""
+
+    __metaclass__ = abc.ABCMeta
+
+    @abc.abstractproperty
+    def backend(self):
+        """Returns the backend this connection is associated with."""
+        pass
+
+    @abc.abstractmethod
+    def close(self):
+        """Closes any resources this connection has open."""
+        pass
+
+    @abc.abstractmethod
+    def upgrade(self):
+        """Migrate the persistence backend to the most recent version."""
+        pass
+
+    @abc.abstractmethod
+    def clear_all(self):
+        """Clear all entries from this backend."""
+        pass
+
+    @abc.abstractmethod
+    def update_task_details(self, task_detail):
+        """Updates a given task details and returns the updated version.
+
+        NOTE(harlowja): the details that is to be updated must already have
+        been created by saving a flow details with the given task detail inside
+        of it.
+        """
+        pass
+
+    @abc.abstractmethod
+    def update_flow_details(self, flow_detail):
+        """Updates a given flow details and returns the updated version.
+
+        NOTE(harlowja): the details that is to be updated must already have
+        been created by saving a logbook with the given flow detail inside
+        of it.
+        """
+        pass
+
+    @abc.abstractmethod
+    def save_logbook(self, book):
+        """Saves a logbook, and all its contained information."""
+        pass
+
+    @abc.abstractmethod
+    def destroy_logbook(self, book_uuid):
+        """Deletes/destroys a logbook matching the given uuid."""
+        pass
+
+    @abc.abstractmethod
+    def get_logbook(self, book_uuid):
+        """Fetches a logbook object matching the given uuid."""
+        pass
+
+    @abc.abstractmethod
+    def get_logbooks(self):
+        """Return an iterable of logbook objects."""
+        pass
diff --git a/taskflow/persistence/backends/impl_memory.py b/taskflow/persistence/backends/impl_memory.py
new file mode 100644
index 000000000..9ba041add
--- /dev/null
+++ b/taskflow/persistence/backends/impl_memory.py
@@ -0,0 +1,204 @@
+# -*- coding: utf-8 -*-
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
+#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+"""Implementation of in-memory backend."""
+
+import copy
+import logging
+import threading
+import weakref
+
+from taskflow import decorators
+from taskflow import exceptions as exc
+from taskflow.openstack.common import timeutils
+from taskflow.persistence.backends import base
+
+LOG = logging.getLogger(__name__)
+
+# TODO(harlowja): we likely need to figure out a better place to put these
+# rather than globals.
+_LOG_BOOKS = {}
+_FLOW_DETAILS = {}
+_TASK_DETAILS = {}
+
+# For now this will be a pretty big lock, since it is not expected that saves
+# will be that frequent this seems ok for the time being. I imagine that this
+# can be done better but it will require much more careful usage of a dict as
+# a key/value map. Aka I wish python had a concurrent dict that was safe and
+# known good to use.
+_SAVE_LOCK = threading.RLock()
+_READ_LOCK = threading.RLock()
+_READ_SAVE_ORDER = (_READ_LOCK, _SAVE_LOCK)
+
+
+def _copy(obj):
+    return copy.deepcopy(obj)
+
+
+class MemoryBackend(base.Backend):
+    def get_connection(self):
+        return Connection(self)
+
+    def close(self):
+        pass
+
+
+class Connection(base.Connection):
+    def __init__(self, backend):
+        self._read_lock = _READ_LOCK
+        self._save_locks = _READ_SAVE_ORDER
+        self._backend = weakref.proxy(backend)
+
+    def upgrade(self):
+        pass
+
+    @property
+    def backend(self):
+        return self._backend
+
+    def close(self):
+        pass
+
+    @decorators.locked(lock="_save_locks")
+    def clear_all(self):
+        count = 0
+        for uuid in list(_LOG_BOOKS.iterkeys()):
+            self.destroy_logbook(uuid)
+            count += 1
+        return count
+
+    @decorators.locked(lock="_save_locks")
+    def destroy_logbook(self, book_uuid):
+        try:
+            # Do the same cascading delete that the sql layer does.
+            lb = _LOG_BOOKS.pop(book_uuid)
+            for fd in lb:
+                _FLOW_DETAILS.pop(fd.uuid, None)
+                for td in fd:
+                    _TASK_DETAILS.pop(td.uuid, None)
+        except KeyError:
+            raise exc.NotFound("No logbook found with id: %s" % book_uuid)
+
+    @decorators.locked(lock="_save_locks")
+    def update_task_details(self, task_detail):
+        try:
+            return _task_details_merge(_TASK_DETAILS[task_detail.uuid],
+                                       task_detail)
+        except KeyError:
+            raise exc.NotFound("No task details found with id: %s"
+                               % task_detail.uuid)
+
+    @decorators.locked(lock="_save_locks")
+    def update_flow_details(self, flow_detail):
+        try:
+            e_fd = _flow_details_merge(_FLOW_DETAILS[flow_detail.uuid],
+                                       flow_detail)
+            for task_detail in flow_detail:
+                if e_fd.find(task_detail.uuid) is None:
+                    _TASK_DETAILS[task_detail.uuid] = _copy(task_detail)
+                    e_fd.add(task_detail)
+                if task_detail.uuid not in _TASK_DETAILS:
+                    _TASK_DETAILS[task_detail.uuid] = _copy(task_detail)
+                task_detail.update(self.update_task_details(task_detail))
+            return e_fd
+        except KeyError:
+            raise exc.NotFound("No flow details found with id: %s"
+                               % flow_detail.uuid)
+
+    @decorators.locked(lock="_save_locks")
+    def save_logbook(self, book):
+        # Get a existing logbook model (or create it if it isn't there).
+        try:
+            e_lb = _logbook_merge(_LOG_BOOKS[book.uuid], book)
+            # Add anything in to the new logbook that isn't already
+            # in the existing logbook.
+            for flow_detail in book:
+                if e_lb.find(flow_detail.uuid) is None:
+                    _FLOW_DETAILS[flow_detail.uuid] = _copy(flow_detail)
+                    e_lb.add(flow_detail)
+                if flow_detail.uuid not in _FLOW_DETAILS:
+                    _FLOW_DETAILS[flow_detail.uuid] = _copy(flow_detail)
+                flow_detail.update(self.update_flow_details(flow_detail))
+            # TODO(harlowja): figure out a better way to set this property
+            # without actually setting a 'private' property.
+            e_lb._updated_at = timeutils.utcnow()
+        except KeyError:
+            # Ok the one given is now the one we will save
+            e_lb = _copy(book)
+            # TODO(harlowja): figure out a better way to set this property
+            # without actually setting a 'private' property.
+            e_lb._created_at = timeutils.utcnow()
+            # Record all the pieces as being saved.
+            _LOG_BOOKS[e_lb.uuid] = e_lb
+            for flow_detail in e_lb:
+                _FLOW_DETAILS[flow_detail.uuid] = _copy(flow_detail)
+                flow_detail.update(self.update_flow_details(flow_detail))
+        return e_lb
+
+    @decorators.locked(lock='_read_lock')
+    def get_logbook(self, book_uuid):
+        try:
+            return _LOG_BOOKS[book_uuid]
+        except KeyError:
+            raise exc.NotFound("No logbook found with id: %s" % book_uuid)
+
+    def get_logbooks(self):
+        # NOTE(harlowja): don't hold the lock while iterating
+        with self._read_lock:
+            books = list(_LOG_BOOKS.values())
+        for lb in books:
+            yield lb
+
+###
+# Merging + other helper functions.
+###
+
+
+def _task_details_merge(td_e, td_new):
+    if td_e is td_new:
+        return td_e
+    if td_e.state != td_new.state:
+        td_e.state = td_new.state
+    if td_e.results != td_new.results:
+        td_e.results = td_new.results
+    if td_e.exception != td_new.exception:
+        td_e.exception = td_new.exception
+    if td_e.stacktrace != td_new.stacktrace:
+        td_e.stacktrace = td_new.stacktrace
+    if td_e.meta != td_new.meta:
+        td_e.meta = td_new.meta
+    return td_e
+
+
+def _flow_details_merge(fd_e, fd_new):
+    if fd_e is fd_new:
+        return fd_e
+    if fd_e.meta != fd_new.meta:
+        fd_e.meta = fd_new.meta
+    if fd_e.state != fd_new.state:
+        fd_e.state = fd_new.state
+    return fd_e
+
+
+def _logbook_merge(lb_e, lb_new):
+    if lb_e is lb_new:
+        return lb_e
+    if lb_e.meta != lb_new.meta:
+        lb_e.meta = lb_new.meta
+    return lb_e
diff --git a/taskflow/persistence/backends/impl_sqlalchemy.py b/taskflow/persistence/backends/impl_sqlalchemy.py
new file mode 100644
index 000000000..1456cbf57
--- /dev/null
+++ b/taskflow/persistence/backends/impl_sqlalchemy.py
@@ -0,0 +1,519 @@
+# -*- coding: utf-8 -*-
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
+#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+"""Implementation of a SQLAlchemy storage backend."""
+
+from __future__ import absolute_import
+
+import contextlib
+import copy
+import logging
+import time
+import weakref
+
+import sqlalchemy as sa
+from sqlalchemy import exceptions as sa_exc
+from sqlalchemy import orm as sa_orm
+from sqlalchemy import pool as sa_pool
+
+from taskflow import exceptions as exc
+from taskflow.persistence.backends import base
+from taskflow.persistence.backends.sqlalchemy import migration
+from taskflow.persistence.backends.sqlalchemy import models
+from taskflow.persistence import logbook
+from taskflow.utils import misc
+
+LOG = logging.getLogger(__name__)
+
+# NOTE(harlowja): This is all very similar to what oslo-incubator uses but is
+# not based on using oslo.cfg and its global configuration (which should not be
+# used in libraries such as taskflow).
+#
+# TODO(harlowja): once oslo.db appears we should be able to use that instead
+# since it's not supposed to have any usage of oslo.cfg in it when it
+# materializes as a library.
+
+# See: http://dev.mysql.com/doc/refman/5.0/en/error-messages-client.html
+MY_SQL_CONN_ERRORS = (
+    # Lost connection to MySQL server at '%s', system error: %d
+    '2006',
+    # Can't connect to MySQL server on '%s' (%d)
+    '2003',
+    # Can't connect to local MySQL server through socket '%s' (%d)
+    '2002',
+)
+MY_SQL_GONE_WAY_AWAY_ERRORS = (
+    # Lost connection to MySQL server at '%s', system error: %d
+    '2006',
+    # Lost connection to MySQL server during query
+    '2013',
+    # Commands out of sync; you can't run this command now
+    '2014',
+    # Can't open shared memory; no answer from server (%lu)
+    '2045',
+    # Lost connection to MySQL server at '%s', system error: %d
+    '2055',
+)
+
+# See: http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
+POSTGRES_CONN_ERRORS = (
+    # connection_exception
+    '08000',
+    # connection_does_not_exist
+    '08003',
+    # connection_failure
+    '08006',
+    # sqlclient_unable_to_establish_sqlconnection
+    '08001',
+    # sqlserver_rejected_establishment_of_sqlconnection
+    '08004',
+    # Just couldn't connect (postgres errors are pretty weird)
+    'could not connect to server',
+)
+POSTGRES_GONE_WAY_AWAY_ERRORS = (
+    # Server terminated while in progress (postgres errors are pretty weird)
+    'server closed the connection unexpectedly',
+    'terminating connection due to administrator command',
+)
+
+# These connection urls mean sqlite is being used as an in-memory DB
+SQLITE_IN_MEMORY = ("sqlite://", 'sqlite:///:memory:')
+
+
+def _in_any(reason, err_haystack):
+    """Checks if any elements of the haystack are in the given reason"""
+    for err in err_haystack:
+        if reason.find(str(err)) != -1:
+            return True
+    return False
+
+
+def _is_db_connection_error(reason):
+    return _in_any(reason, list(MY_SQL_CONN_ERRORS + POSTGRES_CONN_ERRORS))
+
+
+def _thread_yield(dbapi_con, con_record):
+    """Ensure other greenthreads get a chance to be executed.
+
+    If we use eventlet.monkey_patch(), eventlet.greenthread.sleep(0) will
+    execute instead of time.sleep(0).
+
+    Force a context switch. With common database backends (eg MySQLdb and
+    sqlite), there is no implicit yield caused by network I/O since they are
+    implemented by C libraries that eventlet cannot monkey patch.
+    """
+    time.sleep(0)
+
+
+def _ping_listener(dbapi_conn, connection_rec, connection_proxy):
+    """Ensures that MySQL connections checked out of the pool are alive.
+
+    Modified + borrowed from: http://bit.ly/14BYaW6
+    """
+    try:
+        dbapi_conn.cursor().execute('select 1')
+    except dbapi_conn.OperationalError as ex:
+        if _in_any(str(ex.args[0]), MY_SQL_GONE_WAY_AWAY_ERRORS):
+            LOG.warn('Got mysql server has gone away: %s', ex)
+            raise sa_exc.DisconnectionError("Database server went away")
+        elif _in_any(str(ex.args[0]), POSTGRES_GONE_WAY_AWAY_ERRORS):
+            LOG.warn('Got postgres server has gone away: %s', ex)
+            raise sa_exc.DisconnectionError("Database server went away")
+        else:
+            raise
+
+
+class SQLAlchemyBackend(base.Backend):
+    def __init__(self, conf):
+        super(SQLAlchemyBackend, self).__init__(conf)
+        self._engine = None
+        self._session_maker = None
+
+    def _test_connected(self, engine, max_retries=0):
+
+        def test_connect(failures):
+            try:
+                # See if we can make a connection happen.
+                #
+                # NOTE(harlowja): note that even though we are connecting
+                # once it does not mean that we will be able to connect in
+                # the future, so this is more of a sanity test and is not
+                # complete connection insurance.
+                with contextlib.closing(engine.connect()):
+                    pass
+            except sa_exc.OperationalError as ex:
+                if _is_db_connection_error(str(ex.args[0])):
+                    failures.append(misc.Failure())
+                    return False
+            return True
+
+        failures = []
+        if test_connect(failures):
+            return engine
+
+        # Sorry it didn't work out...
+        if max_retries <= 0:
+            failures[-1].reraise()
+
+        # Go through the exponential backoff loop and see if we can connect
+        # after a given number of backoffs (with a backoff sleeping period
+        # between each attempt)...
+        attempts_left = max_retries
+        for sleepy_secs in misc.ExponentialBackoff(attempts=max_retries):
+            LOG.warn("SQL connection failed due to '%s', %s attempts left.",
+                     failures[-1].exc, attempts_left)
+            LOG.info("Attempting to test the connection again in %s seconds.",
+                     sleepy_secs)
+            time.sleep(sleepy_secs)
+            if test_connect(failures):
+                return engine
+            attempts_left -= 1
+
+        # Sorry it didn't work out...
+        failures[-1].reraise()
+
+    def _create_engine(self):
+        # NOTE(harlowja): copy the internal one so that we don't modify it via
+        # all the popping that will happen below.
+        conf = copy.deepcopy(self._conf)
+        engine_args = {
+            'echo': misc.as_bool(conf.pop('echo', False)),
+            'convert_unicode': misc.as_bool(conf.pop('convert_unicode', True)),
+            'pool_recycle': 3600,
+        }
+        try:
+            idle_timeout = misc.as_int(conf.pop('idle_timeout', None))
+            engine_args['pool_recycle'] = idle_timeout
+        except TypeError:
+            pass
+        sql_connection = conf.pop('connection')
+        e_url = sa.engine.url.make_url(sql_connection)
+        if 'sqlite' in e_url.drivername:
+            engine_args["poolclass"] = sa_pool.NullPool
+
+            # Adjustments for in-memory sqlite usage
+            if sql_connection.lower().strip() in SQLITE_IN_MEMORY:
+                engine_args["poolclass"] = sa_pool.StaticPool
+                engine_args["connect_args"] = {'check_same_thread': False}
+        else:
+            for (k, lookup_key) in [('pool_size', 'max_pool_size'),
+                                    ('max_overflow', 'max_overflow'),
+                                    ('pool_timeout', 'pool_timeout')]:
+                try:
+                    engine_args[k] = misc.as_int(conf.pop(lookup_key, None))
+                except TypeError:
+                    pass
+        # If the configuration dict specifies any additional engine args
+        # or engine arg overrides make sure we merge them in.
+        engine_args.update(conf.pop('engine_args', {}))
+        engine = sa.create_engine(sql_connection, **engine_args)
+        if misc.as_bool(conf.pop('checkin_yield', True)):
+            sa.event.listen(engine, 'checkin', _thread_yield)
+        if 'mysql' in e_url.drivername:
+            if misc.as_bool(conf.pop('checkout_ping', True)):
+                sa.event.listen(engine, 'checkout', _ping_listener)
+        try:
+            max_retries = misc.as_int(conf.pop('max_retries', None))
+        except TypeError:
+            max_retries = 0
+        return self._test_connected(engine, max_retries=max_retries)
+
+    @property
+    def engine(self):
+        if self._engine is None:
+            self._engine = self._create_engine()
+        return self._engine
+
+    def _get_session_maker(self):
+        if self._session_maker is None:
+            self._session_maker = sa_orm.sessionmaker(bind=self.engine,
+                                                      autocommit=True)
+        return self._session_maker
+
+    def get_connection(self):
+        return Connection(self, self._get_session_maker())
+
+    def close(self):
+        if self._session_maker is not None:
+            self._session_maker.close_all()
+        if self._engine is not None:
+            self._engine.dispose()
+        self._engine = None
+        self._session_maker = None
+
+
+class Connection(base.Connection):
+    def __init__(self, backend, session_maker):
+        self._backend = weakref.proxy(backend)
+        self._session_maker = session_maker
+        self._engine = backend.engine
+
+    @property
+    def backend(self):
+        return self._backend
+
+    def _run_in_session(self, functor, *args, **kwargs):
+        """Runs a function in a session and makes sure that sqlalchemy
+        exceptions aren't emitted from that sessions actions (as that would
+        expose the underlying backends exception model).
+        """
+        try:
+            session = self._make_session()
+            with session.begin():
+                return functor(session, *args, **kwargs)
+        except sa_exc.SQLAlchemyError as e:
+            raise exc.StorageError("Failed running database session: %s" % e,
+                                   e)
+
+    def _make_session(self):
+        try:
+            return self._session_maker()
+        except sa_exc.SQLAlchemyError as e:
+            raise exc.StorageError("Failed creating database session: %s"
+                                   % e, e)
+
+    def upgrade(self):
+        try:
+            with contextlib.closing(self._engine.connect()) as conn:
+                migration.db_sync(conn)
+        except sa_exc.SQLAlchemyError as e:
+            raise exc.StorageError("Failed upgrading database version: %s" % e,
+                                   e)
+
+    def _clear_all(self, session):
+        # NOTE(harlowja): due to how we have our relationship setup and
+        # cascading deletes are enabled, this will cause all associated
+        # task details and flow details to automatically be purged.
+        try:
+            return session.query(models.LogBook).delete()
+        except sa_exc.DBAPIError as e:
+            raise exc.StorageError("Failed clearing all entries: %s" % e, e)
+
+    def clear_all(self):
+        return self._run_in_session(self._clear_all)
+
+    def _update_task_details(self, session, td):
+        # Must already exist since a tasks details has a strong connection to
+        # a flow details, and tasks details can not be saved on there own since
+        # they *must* have a connection to an existing flow details.
+        td_m = _task_details_get_model(td.uuid, session=session)
+        td_m = _taskdetails_merge(td_m, td)
+        td_m = session.merge(td_m)
+        return _convert_td_to_external(td_m)
+
+    def update_task_details(self, task_detail):
+        return self._run_in_session(self._update_task_details, td=task_detail)
+
+    def _update_flow_details(self, session, fd):
+        # Must already exist since a flow details has a strong connection to
+        # a logbook, and flow details can not be saved on there own since they
+        # *must* have a connection to an existing logbook.
+        fd_m = _flow_details_get_model(fd.uuid, session=session)
+        fd_m = _flowdetails_merge(fd_m, fd)
+        fd_m = session.merge(fd_m)
+        return _convert_fd_to_external(fd_m)
+
+    def update_flow_details(self, flow_detail):
+        return self._run_in_session(self._update_flow_details, fd=flow_detail)
+
+    def _destroy_logbook(self, session, lb_id):
+        try:
+            lb = _logbook_get_model(lb_id, session=session)
+            session.delete(lb)
+        except sa_exc.DBAPIError as e:
+            raise exc.StorageError("Failed destroying"
+                                   " logbook %s: %s" % (lb_id, e), e)
+
+    def destroy_logbook(self, book_uuid):
+        return self._run_in_session(self._destroy_logbook, lb_id=book_uuid)
+
+    def _save_logbook(self, session, lb):
+        try:
+            lb_m = _logbook_get_model(lb.uuid, session=session)
+            # NOTE(harlowja): Merge them (note that this doesn't provide
+            # 100% correct update semantics due to how databases have
+            # MVCC). This is where a stored procedure or a better backing
+            # store would handle this better by allowing this merge logic
+            # to exist in the database itself.
+            lb_m = _logbook_merge(lb_m, lb)
+        except exc.NotFound:
+            lb_m = _convert_lb_to_internal(lb)
+        try:
+            lb_m = session.merge(lb_m)
+            return _convert_lb_to_external(lb_m)
+        except sa_exc.DBAPIError as e:
+            raise exc.StorageError("Failed saving logbook %s: %s" %
+                                   (lb.uuid, e), e)
+
+    def save_logbook(self, book):
+        return self._run_in_session(self._save_logbook, lb=book)
+
+    def get_logbook(self, book_uuid):
+        session = self._make_session()
+        try:
+            lb = _logbook_get_model(book_uuid, session=session)
+            return _convert_lb_to_external(lb)
+        except sa_exc.DBAPIError as e:
+            raise exc.StorageError("Failed getting logbook %s: %s"
+                                   % (book_uuid, e), e)
+
+    def get_logbooks(self):
+        session = self._make_session()
+        try:
+            raw_books = session.query(models.LogBook).all()
+            books = [_convert_lb_to_external(lb) for lb in raw_books]
+        except sa_exc.DBAPIError as e:
+            raise exc.StorageError("Failed getting logbooks: %s" % e, e)
+        for lb in books:
+            yield lb
+
+    def close(self):
+        pass
+
+###
+# Internal <-> external model + merging + other helper functions.
+###
+
+
+def _convert_fd_to_external(fd):
+    fd_c = logbook.FlowDetail(fd.name, uuid=fd.uuid)
+    fd_c.meta = fd.meta
+    fd_c.state = fd.state
+    for td in fd.taskdetails:
+        fd_c.add(_convert_td_to_external(td))
+    return fd_c
+
+
+def _convert_fd_to_internal(fd, parent_uuid):
+    fd_m = models.FlowDetail(name=fd.name, uuid=fd.uuid,
+                             parent_uuid=parent_uuid, meta=fd.meta,
+                             state=fd.state)
+    fd_m.taskdetails = []
+    for td in fd:
+        fd_m.taskdetails.append(_convert_td_to_internal(td, fd_m.uuid))
+    return fd_m
+
+
+def _convert_td_to_internal(td, parent_uuid):
+    return models.TaskDetail(name=td.name, uuid=td.uuid,
+                             state=td.state, results=td.results,
+                             exception=td.exception, meta=td.meta,
+                             stacktrace=td.stacktrace,
+                             version=td.version, parent_uuid=parent_uuid)
+
+
+def _convert_td_to_external(td):
+    # Convert from sqlalchemy model -> external model, this allows us
+    # to change the internal sqlalchemy model easily by forcing a defined
+    # interface (that isn't the sqlalchemy model itself).
+    td_c = logbook.TaskDetail(td.name, uuid=td.uuid)
+    td_c.state = td.state
+    td_c.results = td.results
+    td_c.exception = td.exception
+    td_c.stacktrace = td.stacktrace
+    td_c.meta = td.meta
+    td_c.version = td.version
+    return td_c
+
+
+def _convert_lb_to_external(lb_m):
+    """Don't expose the internal sqlalchemy ORM model to the external api."""
+    lb_c = logbook.LogBook(lb_m.name, lb_m.uuid,
+                           updated_at=lb_m.updated_at,
+                           created_at=lb_m.created_at)
+    lb_c.meta = lb_m.meta
+    for fd_m in lb_m.flowdetails:
+        lb_c.add(_convert_fd_to_external(fd_m))
+    return lb_c
+
+
+def _convert_lb_to_internal(lb_c):
+    """Don't expose the external model to the sqlalchemy ORM model."""
+    lb_m = models.LogBook(uuid=lb_c.uuid, meta=lb_c.meta, name=lb_c.name)
+    lb_m.flowdetails = []
+    for fd_c in lb_c:
+        lb_m.flowdetails.append(_convert_fd_to_internal(fd_c, lb_c.uuid))
+    return lb_m
+
+
+def _logbook_get_model(lb_id, session):
+    entry = session.query(models.LogBook).filter_by(uuid=lb_id).first()
+    if entry is None:
+        raise exc.NotFound("No logbook found with id: %s" % lb_id)
+    return entry
+
+
+def _flow_details_get_model(f_id, session):
+    entry = session.query(models.FlowDetail).filter_by(uuid=f_id).first()
+    if entry is None:
+        raise exc.NotFound("No flow details found with id: %s" % f_id)
+    return entry
+
+
+def _task_details_get_model(t_id, session):
+    entry = session.query(models.TaskDetail).filter_by(uuid=t_id).first()
+    if entry is None:
+        raise exc.NotFound("No task details found with id: %s" % t_id)
+    return entry
+
+
+def _logbook_merge(lb_m, lb):
+    if lb_m.meta != lb.meta:
+        lb_m.meta = lb.meta
+    for fd in lb:
+        existing_fd = False
+        for fd_m in lb_m.flowdetails:
+            if fd_m.uuid == fd.uuid:
+                existing_fd = True
+                fd_m = _flowdetails_merge(fd_m, fd)
+        if not existing_fd:
+            lb_m.flowdetails.append(_convert_fd_to_internal(fd, lb_m.uuid))
+    return lb_m
+
+
+def _flowdetails_merge(fd_m, fd):
+    if fd_m.meta != fd.meta:
+        fd_m.meta = fd.meta
+    if fd_m.state != fd.state:
+        fd_m.state = fd.state
+    for td in fd:
+        existing_td = False
+        for td_m in fd_m.taskdetails:
+            if td_m.uuid == td.uuid:
+                existing_td = True
+                td_m = _taskdetails_merge(td_m, td)
+                break
+        if not existing_td:
+            td_m = _convert_td_to_internal(td, fd_m.uuid)
+            fd_m.taskdetails.append(td_m)
+    return fd_m
+
+
+def _taskdetails_merge(td_m, td):
+    if td_m.state != td.state:
+        td_m.state = td.state
+    if td_m.results != td.results:
+        td_m.results = td.results
+    if td_m.exception != td.exception:
+        td_m.exception = td.exception
+    if td_m.stacktrace != td.stacktrace:
+        td_m.stacktrace = td.stacktrace
+    if td_m.meta != td.meta:
+        td_m.meta = td.meta
+    return td_m
diff --git a/taskflow/persistence/backends/memory/__init__.py b/taskflow/persistence/backends/memory/__init__.py
deleted file mode 100644
index 275e7e13c..000000000
--- a/taskflow/persistence/backends/memory/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
-#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
diff --git a/taskflow/persistence/backends/memory/api.py b/taskflow/persistence/backends/memory/api.py
deleted file mode 100644
index 06375d909..000000000
--- a/taskflow/persistence/backends/memory/api.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
-#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""Implementation of in-memory backend."""
-
-import copy
-import logging
-import sys
-import threading
-
-from taskflow import exceptions as exc
-from taskflow.openstack.common import timeutils
-from taskflow.utils import threading_utils
-
-LOG = logging.getLogger(__name__)
-
-# TODO(harlowja): we likely need to figure out a better place to put these
-# rather than globals.
-LOG_BOOKS = {}
-FLOW_DETAILS = {}
-TASK_DETAILS = {}
-
-# For now this will be a pretty big lock, since it is not expected that saves
-# will be that frequent this seems ok for the time being. I imagine that this
-# can be done better but it will require much more careful usage of a dict as
-# a key/value map. Aka I wish python had a concurrent dict that was safe and
-# known good to use.
-SAVE_LOCK = threading.RLock()
-READ_LOCK = threading.RLock()
-READ_SAVE_ORDER = (READ_LOCK, SAVE_LOCK,)
-
-
-def get_backend():
-    """The backend is this module itself."""
-    return sys.modules[__name__]
-
-
-def _taskdetails_merge(td_e, td_new):
-    """Merges an existing taskdetails with a new one."""
-    if td_e.state != td_new.state:
-        td_e.state = td_new.state
-    if td_e.results != td_new.results:
-        td_e.results = td_new.results
-    if td_e.exception != td_new.exception:
-        td_e.exception = td_new.exception
-    if td_e.stacktrace != td_new.stacktrace:
-        td_e.stacktrace = td_new.stacktrace
-    if td_e.meta != td_new.meta:
-        td_e.meta = td_new.meta
-    return td_e
-
-
-def taskdetails_save(td):
-    with threading_utils.MultiLock(READ_SAVE_ORDER):
-        try:
-            return _taskdetails_merge(TASK_DETAILS[td.uuid], td)
-        except KeyError:
-            raise exc.NotFound("No task details found with id: %s" % td.uuid)
-
-
-def flowdetails_save(fd):
-    try:
-        with threading_utils.MultiLock(READ_SAVE_ORDER):
-            e_fd = FLOW_DETAILS[fd.uuid]
-            if e_fd.meta != fd.meta:
-                e_fd.meta = fd.meta
-            if e_fd.state != fd.state:
-                e_fd.state = fd.state
-            for td in fd:
-                if td not in e_fd:
-                    td = copy.deepcopy(td)
-                    TASK_DETAILS[td.uuid] = td
-                    e_fd.add(td)
-                else:
-                    # Previously added but not saved into the taskdetails
-                    # 'permanent' storage.
-                    if td.uuid not in TASK_DETAILS:
-                        TASK_DETAILS[td.uuid] = copy.deepcopy(td)
-                    taskdetails_save(td)
-            return e_fd
-    except KeyError:
-        raise exc.NotFound("No flow details found with id: %s" % fd.uuid)
-
-
-def clear_all():
-    with threading_utils.MultiLock(READ_SAVE_ORDER):
-        count = 0
-        for lb_id in list(LOG_BOOKS.iterkeys()):
-            logbook_destroy(lb_id)
-            count += 1
-        return count
-
-
-def logbook_get(lb_id):
-    try:
-        with READ_LOCK:
-            return LOG_BOOKS[lb_id]
-    except KeyError:
-        raise exc.NotFound("No logbook found with id: %s" % lb_id)
-
-
-def logbook_destroy(lb_id):
-    try:
-        with threading_utils.MultiLock(READ_SAVE_ORDER):
-            # Do the same cascading delete that the sql layer does.
-            lb = LOG_BOOKS.pop(lb_id)
-            for fd in lb:
-                FLOW_DETAILS.pop(fd.uuid, None)
-                for td in fd:
-                    TASK_DETAILS.pop(td.uuid, None)
-    except KeyError:
-        raise exc.NotFound("No logbook found with id: %s" % lb_id)
-
-
-def logbook_save(lb):
-    # Acquire all the locks that will be needed to perform this operation with
-    # out being affected by other threads doing it at the same time.
-    with threading_utils.MultiLock(READ_SAVE_ORDER):
-        # Get a existing logbook model (or create it if it isn't there).
-        try:
-            backing_lb = LOG_BOOKS[lb.uuid]
-            if backing_lb.meta != lb.meta:
-                backing_lb.meta = lb.meta
-            # Add anything on to the existing loaded logbook that isn't already
-            # in the existing logbook.
-            for fd in lb:
-                if fd not in backing_lb:
-                    FLOW_DETAILS[fd.uuid] = copy.deepcopy(fd)
-                    backing_lb.add(flowdetails_save(fd))
-                else:
-                    # Previously added but not saved into the flowdetails
-                    # 'permanent' storage.
-                    if fd.uuid not in FLOW_DETAILS:
-                        FLOW_DETAILS[fd.uuid] = copy.deepcopy(fd)
-                    flowdetails_save(fd)
-            # TODO(harlowja): figure out a better way to set this property
-            # without actually letting others set it external.
-            backing_lb._updated_at = timeutils.utcnow()
-        except KeyError:
-            backing_lb = copy.deepcopy(lb)
-            # TODO(harlowja): figure out a better way to set this property
-            # without actually letting others set it external.
-            backing_lb._created_at = timeutils.utcnow()
-            # Record all the pieces as being saved.
-            LOG_BOOKS[lb.uuid] = backing_lb
-            for fd in backing_lb:
-                FLOW_DETAILS[fd.uuid] = fd
-                for td in fd:
-                    TASK_DETAILS[td.uuid] = td
-        return backing_lb
diff --git a/taskflow/persistence/backends/sqlalchemy/api.py b/taskflow/persistence/backends/sqlalchemy/api.py
deleted file mode 100644
index 1dc043765..000000000
--- a/taskflow/persistence/backends/sqlalchemy/api.py
+++ /dev/null
@@ -1,246 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
-#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""Implementation of a SQLAlchemy storage backend."""
-
-import logging
-import sys
-
-from sqlalchemy import exceptions as sql_exc
-
-from taskflow import exceptions as exc
-from taskflow.openstack.common.db.sqlalchemy import session as db_session
-from taskflow.persistence.backends.sqlalchemy import models
-from taskflow.persistence import flowdetail
-from taskflow.persistence import logbook
-from taskflow.persistence import taskdetail
-
-
-LOG = logging.getLogger(__name__)
-
-
-def get_backend():
-    """The backend is this module itself."""
-    return sys.modules[__name__]
-
-
-def _convert_fd_to_external(fd):
-    fd_c = flowdetail.FlowDetail(fd.name, uuid=fd.uuid, backend='sqlalchemy')
-    fd_c.meta = fd.meta
-    fd_c.state = fd.state
-    for td in fd.taskdetails:
-        fd_c.add(_convert_td_to_external(td))
-    return fd_c
-
-
-def _convert_fd_to_internal(fd, lb_uuid):
-    fd_m = models.FlowDetail(name=fd.name, uuid=fd.uuid, parent_uuid=lb_uuid,
-                             meta=fd.meta, state=fd.state)
-    fd_m.taskdetails = []
-    for td in fd:
-        fd_m.taskdetails.append(_convert_td_to_internal(td, fd_m.uuid))
-    return fd_m
-
-
-def _convert_td_to_internal(td, parent_uuid):
-    return models.TaskDetail(name=td.name, uuid=td.uuid,
-                             state=td.state, results=td.results,
-                             exception=td.exception, meta=td.meta,
-                             stacktrace=td.stacktrace,
-                             version=td.version, parent_uuid=parent_uuid)
-
-
-def _convert_td_to_external(td):
-    # Convert from sqlalchemy model -> external model, this allows us
-    # to change the internal sqlalchemy model easily by forcing a defined
-    # interface (that isn't the sqlalchemy model itself).
-    td_c = taskdetail.TaskDetail(td.name, uuid=td.uuid, backend='sqlalchemy')
-    td_c.state = td.state
-    td_c.results = td.results
-    td_c.exception = td.exception
-    td_c.stacktrace = td.stacktrace
-    td_c.meta = td.meta
-    td_c.version = td.version
-    return td_c
-
-
-def _convert_lb_to_external(lb_m):
-    """Don't expose the internal sqlalchemy ORM model to the external api."""
-    lb_c = logbook.LogBook(lb_m.name, lb_m.uuid,
-                           updated_at=lb_m.updated_at,
-                           created_at=lb_m.created_at,
-                           backend='sqlalchemy')
-    lb_c.meta = lb_m.meta
-    for fd_m in lb_m.flowdetails:
-        lb_c.add(_convert_fd_to_external(fd_m))
-    return lb_c
-
-
-def _convert_lb_to_internal(lb_c):
-    """Don't expose the external model to the sqlalchemy ORM model."""
-    lb_m = models.LogBook(uuid=lb_c.uuid, meta=lb_c.meta, name=lb_c.name)
-    lb_m.flowdetails = []
-    for fd_c in lb_c:
-        lb_m.flowdetails.append(_convert_fd_to_internal(fd_c, lb_c.uuid))
-    return lb_m
-
-
-def _logbook_get_model(lb_id, session):
-    entry = session.query(models.LogBook).filter_by(uuid=lb_id).first()
-    if entry is None:
-        raise exc.NotFound("No logbook found with id: %s" % lb_id)
-    return entry
-
-
-def _flow_details_get_model(f_id, session):
-    entry = session.query(models.FlowDetail).filter_by(uuid=f_id).first()
-    if entry is None:
-        raise exc.NotFound("No flow details found with id: %s" % f_id)
-    return entry
-
-
-def _task_details_get_model(t_id, session):
-    entry = session.query(models.TaskDetail).filter_by(uuid=t_id).first()
-    if entry is None:
-        raise exc.NotFound("No task details found with id: %s" % t_id)
-    return entry
-
-
-def _taskdetails_merge(td_m, td):
-    if td_m.state != td.state:
-        td_m.state = td.state
-    if td_m.results != td.results:
-        td_m.results = td.results
-    if td_m.exception != td.exception:
-        td_m.exception = td.exception
-    if td_m.stacktrace != td.stacktrace:
-        td_m.stacktrace = td.stacktrace
-    if td_m.meta != td.meta:
-        td_m.meta = td.meta
-    return td_m
-
-
-def clear_all():
-    session = db_session.get_session()
-    with session.begin():
-        # NOTE(harlowja): due to how we have our relationship setup and
-        # cascading deletes are enabled, this will cause all associated task
-        # details and flow details to automatically be purged.
-        try:
-            return session.query(models.LogBook).delete()
-        except sql_exc.DBAPIError as e:
-            raise exc.StorageError("Failed clearing all entries: %s" % e, e)
-
-
-def taskdetails_save(td):
-    # Must already exist since a tasks details has a strong connection to
-    # a flow details, and tasks details can not be saved on there own since
-    # they *must* have a connection to an existing flow details.
-    session = db_session.get_session()
-    with session.begin():
-        td_m = _task_details_get_model(td.uuid, session=session)
-        td_m = _taskdetails_merge(td_m, td)
-        td_m = session.merge(td_m)
-        return _convert_td_to_external(td_m)
-
-
-def flowdetails_save(fd):
-    # Must already exist since a flow details has a strong connection to
-    # a logbook, and flow details can not be saved on there own since they
-    # *must* have a connection to an existing logbook.
-    session = db_session.get_session()
-    with session.begin():
-        fd_m = _flow_details_get_model(fd.uuid, session=session)
-        if fd_m.meta != fd.meta:
-            fd_m.meta = fd.meta
-        if fd_m.state != fd.state:
-            fd_m.state = fd.state
-        for td in fd:
-            updated = False
-            for td_m in fd_m.taskdetails:
-                if td_m.uuid == td.uuid:
-                    updated = True
-                    td_m = _taskdetails_merge(td_m, td)
-                    break
-            if not updated:
-                fd_m.taskdetails.append(_convert_td_to_internal(td, fd_m.uuid))
-        fd_m = session.merge(fd_m)
-        return _convert_fd_to_external(fd_m)
-
-
-def logbook_destroy(lb_id):
-    session = db_session.get_session()
-    with session.begin():
-        try:
-            lb = _logbook_get_model(lb_id, session=session)
-            session.delete(lb)
-        except sql_exc.DBAPIError as e:
-            raise exc.StorageError("Failed destroying"
-                                   " logbook %s: %s" % (lb_id, e), e)
-
-
-def logbook_save(lb):
-    session = db_session.get_session()
-    with session.begin():
-        try:
-            lb_m = _logbook_get_model(lb.uuid, session=session)
-            # NOTE(harlowja): Merge them (note that this doesn't provide 100%
-            # correct update semantics due to how databases have MVCC). This
-            # is where a stored procedure or a better backing store would
-            # handle this better (something more suited to this type of data).
-            for fd in lb:
-                existing_fd = False
-                for fd_m in lb_m.flowdetails:
-                    if fd_m.uuid == fd.uuid:
-                        existing_fd = True
-                        if fd_m.meta != fd.meta:
-                            fd_m.meta = fd.meta
-                        if fd_m.state != fd.state:
-                            fd_m.state = fd.state
-                        for td in fd:
-                            existing_td = False
-                            for td_m in fd_m.taskdetails:
-                                if td_m.uuid == td.uuid:
-                                    existing_td = True
-                                    td_m = _taskdetails_merge(td_m, td)
-                                    break
-                            if not existing_td:
-                                td_m = _convert_td_to_internal(td, fd_m.uuid)
-                                fd_m.taskdetails.append(td_m)
-                if not existing_fd:
-                    lb_m.flowdetails.append(_convert_fd_to_internal(fd,
-                                                                    lb_m.uuid))
-        except exc.NotFound:
-            lb_m = _convert_lb_to_internal(lb)
-        try:
-            lb_m = session.merge(lb_m)
-            return _convert_lb_to_external(lb_m)
-        except sql_exc.DBAPIError as e:
-            raise exc.StorageError("Failed saving"
-                                   " logbook %s: %s" % (lb.uuid, e), e)
-
-
-def logbook_get(lb_id):
-    session = db_session.get_session()
-    try:
-        lb_m = _logbook_get_model(lb_id, session=session)
-        return _convert_lb_to_external(lb_m)
-    except sql_exc.DBAPIError as e:
-        raise exc.StorageError("Failed getting"
-                               " logbook %s: %s" % (lb_id, e), e)
diff --git a/taskflow/persistence/backends/sqlalchemy/migration.py b/taskflow/persistence/backends/sqlalchemy/migration.py
index 89c27c29c..52ac7c957 100644
--- a/taskflow/persistence/backends/sqlalchemy/migration.py
+++ b/taskflow/persistence/backends/sqlalchemy/migration.py
@@ -20,25 +20,25 @@
 
 import os
 
-from oslo.config import cfg
-
-import alembic
-from alembic import config as alembic_config
-
-CONF = cfg.CONF
-CONF.import_opt('connection',
-                'taskflow.openstack.common.db.sqlalchemy.session',
-                group='database')
+from alembic import config as a_config
+from alembic import environment as a_env
+from alembic import script as a_script
 
 
 def _alembic_config():
     path = os.path.join(os.path.dirname(__file__), 'alembic', 'alembic.ini')
-    config = alembic_config.Config(path)
-    if not config.get_main_option('url'):
-        config.set_main_option('sqlalchemy.url', CONF.database.connection)
-    return config
+    return a_config.Config(path)
 
 
-def db_sync():
+def db_sync(connection, revision='head'):
+    script = a_script.ScriptDirectory.from_config(_alembic_config())
+
+    def upgrade(rev, context):
+        return script._upgrade_revs(revision, rev)
+
     config = _alembic_config()
-    alembic.command.upgrade(config, "head")
+    with a_env.EnvironmentContext(config, script, fn=upgrade, as_sql=False,
+                                  starting_rev=None, destination_rev=revision,
+                                  tag=None) as context:
+        context.configure(connection=connection)
+        context.run_migrations()
diff --git a/taskflow/persistence/backends/sqlalchemy/models.py b/taskflow/persistence/backends/sqlalchemy/models.py
index bc3e48181..59894ca70 100644
--- a/taskflow/persistence/backends/sqlalchemy/models.py
+++ b/taskflow/persistence/backends/sqlalchemy/models.py
@@ -25,6 +25,7 @@ from sqlalchemy.orm import relationship
 from sqlalchemy import types as types
 
 from taskflow.openstack.common.db.sqlalchemy import models as c_models
+
 from taskflow.openstack.common import jsonutils
 from taskflow.openstack.common import uuidutils
 
@@ -41,8 +42,7 @@ class Json(types.TypeDecorator, types.MutableType):
         return jsonutils.loads(value)
 
 
-class ModelBase(c_models.ModelBase,
-                c_models.TimestampMixin):
+class ModelBase(c_models.ModelBase, c_models.TimestampMixin):
     """Base model for all taskflow objects"""
     uuid = Column(String, default=uuidutils.generate_uuid,
                   primary_key=True, nullable=False, unique=True)
diff --git a/taskflow/persistence/flowdetail.py b/taskflow/persistence/flowdetail.py
deleted file mode 100644
index 2cad3a2d8..000000000
--- a/taskflow/persistence/flowdetail.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from taskflow.persistence.backends import api as b_api
-
-
-class FlowDetail(object):
-    """This class contains an append-only list of task detail entries for a
-    given flow along with any metadata associated with that flow.
-
-    The data contained within this class need *not* backed by the backend
-    storage in real time. The data in this class will only be guaranteed to be
-    persisted when the logbook that contains this flow detail is saved or when
-    the save() method is called directly.
-    """
-    def __init__(self, name, uuid, backend='memory'):
-        self._uuid = uuid
-        self._name = name
-        self._taskdetails = []
-        self.state = None
-        # Any other metadata to include about this flow while storing. For
-        # example timing information could be stored here, other misc. flow
-        # related items (edge connections)...
-        self.meta = None
-        self.backend = backend
-
-    def _get_backend(self):
-        if not self.backend:
-            return None
-        return b_api.fetch(self.backend)
-
-    def add(self, td):
-        self._taskdetails.append(td)
-        # When added the backend that the task details is using will be
-        # automatically switched to whatever backend this flow details is
-        # using.
-        if td.backend != self.backend:
-            td.backend = self.backend
-
-    def find(self, td_uuid):
-        for self_td in self:
-            if self_td.uuid == td_uuid:
-                return self_td
-        return None
-
-    def find_by_name(self, td_name):
-        for self_td in self:
-            if self_td.name == td_name:
-                return self_td
-        return None
-
-    def save(self):
-        """Saves *most* of the components of this given object.
-
-        This will immediately and atomically save the attributes of this flow
-        details object to a backing store providing by the backing api.
-
-        The underlying storage must contain an existing flow details that this
-        save operation will merge with and then reflect those changes in this
-        object.
-        """
-        backend = self._get_backend()
-        if not backend:
-            raise NotImplementedError("No saving backend provided")
-        fd_u = backend.flowdetails_save(self)
-        if fd_u is self:
-            return
-        self.meta = fd_u.meta
-        self.state = fd_u.state
-        self._taskdetails = fd_u._taskdetails
-
-    @property
-    def uuid(self):
-        return self._uuid
-
-    @property
-    def name(self):
-        return self._name
-
-    def __iter__(self):
-        for td in self._taskdetails:
-            yield td
-
-    def __len__(self):
-        return len(self._taskdetails)
diff --git a/taskflow/persistence/logbook.py b/taskflow/persistence/logbook.py
index dcced943a..ca28d74c2 100644
--- a/taskflow/persistence/logbook.py
+++ b/taskflow/persistence/logbook.py
@@ -2,7 +2,8 @@
 
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
+#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
+#    Copyright (C) 2013 Rackspace Hosting All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -16,8 +17,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import logging
+
 from taskflow.openstack.common import uuidutils
-from taskflow.persistence.backends import api as b_api
+
+LOG = logging.getLogger(__name__)
 
 
 class LogBook(object):
@@ -27,10 +31,9 @@ class LogBook(object):
 
     The data contained within this class need *not* backed by the backend
     storage in real time. The data in this class will only be guaranteed to be
-    persisted when the logbook is saved.
+    persisted when a save occurs via some backend connection.
     """
-    def __init__(self, name, uuid=None, updated_at=None, created_at=None,
-                 backend='memory'):
+    def __init__(self, name, uuid=None, updated_at=None, created_at=None):
         if uuid:
             self._uuid = uuid
         else:
@@ -39,14 +42,8 @@ class LogBook(object):
         self._flowdetails = []
         self._updated_at = updated_at
         self._created_at = created_at
-        self.backend = backend
         self.meta = None
 
-    def _get_backend(self):
-        if not self.backend:
-            return None
-        return b_api.fetch(self.backend)
-
     @property
     def created_at(self):
         return self._created_at
@@ -55,59 +52,12 @@ class LogBook(object):
     def updated_at(self):
         return self._updated_at
 
-    def save(self):
-        """Saves all the components of the given logbook.
-
-        This will immediately and atomically save all the entries of the given
-        logbook, including any flow details, and any associated task details,
-        that may be contained in this logbook to a backing store providing by
-        the backing api.
-
-        If the logbook is the underlying storage contains an existing logbook
-        then this save operation will merge the different flow details objects
-        to that logbook and then reflect those changes in this logbook.
-        """
-        backend = self._get_backend()
-        if not backend:
-            raise NotImplementedError("No saving backend provided")
-        s_book = backend.logbook_save(self)
-        if s_book is self:
-            return
-        # Alter the internal variables to reflect what was saved (which may
-        # have new additions if there was a merge with pre-existing data).
-        self._name = s_book._name
-        self._flowdetails = s_book._flowdetails
-        self._updated_at = s_book._updated_at
-        self._created_at = s_book._created_at
-        self.meta = s_book.meta
-
-    def delete(self):
-        """Deletes all traces of the given logbook.
-
-        This will delete the logbook entry, any associated flow detail entries
-        and any associated task detail entries associated with those flow
-        detail entries immediately via the backing api (using a atomic
-        transaction).
-        """
-        backend = self._get_backend()
-        if not backend:
-            raise NotImplementedError("No deleting backend provided")
-        backend.logbook_destroy(self.uuid)
-
     def add(self, flow_detail):
         """Adds a new entry to the underlying logbook.
 
         Does not *guarantee* that the details will be immediatly saved.
         """
         self._flowdetails.append(flow_detail)
-        # When added the backend that the flow details (and any owned task
-        # details) is using will be automatically switched to whatever backend
-        # this logbook is using.
-        if flow_detail.backend != self.backend:
-            flow_detail.backend = self.backend
-        for task_detail in flow_detail:
-            if task_detail.backend != self.backend:
-                task_detail.backend = self.backend
 
     def find(self, flow_uuid):
         for fd in self._flowdetails:
@@ -131,6 +81,115 @@ class LogBook(object):
         return len(self._flowdetails)
 
 
-def load(lb_id, backend='memory'):
-    """Loads a given logbook (if it exists) from the given backend type."""
-    return b_api.fetch(backend).logbook_get(lb_id)
+class FlowDetail(object):
+    """This class contains an append-only list of task detail entries for a
+    given flow along with any metadata associated with that flow.
+
+    The data contained within this class need *not* backed by the backend
+    storage in real time. The data in this class will only be guaranteed to be
+    persisted when a save/update occurs via some backend connection.
+    """
+    def __init__(self, name, uuid):
+        self._uuid = uuid
+        self._name = name
+        self._taskdetails = []
+        self.state = None
+        # Any other metadata to include about this flow while storing. For
+        # example timing information could be stored here, other misc. flow
+        # related items (edge connections)...
+        self.meta = None
+
+    def update(self, fd):
+        """Updates the objects state to be the same as the given one."""
+        if fd is self:
+            return
+        self._taskdetails = list(fd._taskdetails)
+        self.state = fd.state
+        self.meta = fd.meta
+
+    def add(self, td):
+        self._taskdetails.append(td)
+
+    def find(self, td_uuid):
+        for self_td in self:
+            if self_td.uuid == td_uuid:
+                return self_td
+        return None
+
+    def find_by_name(self, td_name):
+        for self_td in self:
+            if self_td.name == td_name:
+                return self_td
+        return None
+
+    @property
+    def uuid(self):
+        return self._uuid
+
+    @property
+    def name(self):
+        return self._name
+
+    def __iter__(self):
+        for td in self._taskdetails:
+            yield td
+
+    def __len__(self):
+        return len(self._taskdetails)
+
+
+class TaskDetail(object):
+    """This class contains an entry that contains the persistance of a task
+    after or before (or during) it is running including any results it may have
+    produced, any state that it may be in (failed for example), any exception
+    that occured when running and any associated stacktrace that may have
+    occuring during that exception being thrown and any other metadata that
+    should be stored along-side the details about this task.
+
+    The data contained within this class need *not* backed by the backend
+    storage in real time. The data in this class will only be guaranteed to be
+    persisted when a save/update occurs via some backend connection.
+    """
+    def __init__(self, name, uuid):
+        self._uuid = uuid
+        self._name = name
+        # TODO(harlowja): decide if these should be passed in and therefore
+        # immutable or let them be assigned?
+        #
+        # The state the task was last in.
+        self.state = None
+        # The results it may have produced (useful for reverting).
+        self.results = None
+        # An exception that it may have thrown (or part of it), useful for
+        # knowing what failed.
+        self.exception = None
+        # Any stack trace the exception may have had, useful for debugging or
+        # examining the failure in more depth.
+        self.stacktrace = None
+        # Any other metadata to include about this task while storing. For
+        # example timing information could be stored here, other misc. task
+        # related items.
+        self.meta = None
+        # The version of the task this task details was associated with which
+        # is quite useful for determining what versions of tasks this detail
+        # information can be associated with.
+        self.version = None
+
+    def update(self, td):
+        """Updates the objects state to be the same as the given one."""
+        if td is self:
+            return
+        self.state = td.state
+        self.meta = td.meta
+        self.stacktrace = td.stacktrace
+        self.exception = td.exception
+        self.results = td.results
+        self.version = td.version
+
+    @property
+    def uuid(self):
+        return self._uuid
+
+    @property
+    def name(self):
+        return self._name
diff --git a/taskflow/persistence/taskdetail.py b/taskflow/persistence/taskdetail.py
deleted file mode 100644
index ba135c99a..000000000
--- a/taskflow/persistence/taskdetail.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#    Copyright (C) 2013 Rackspace Hosting Inc. All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from taskflow.persistence.backends import api as b_api
-
-
-class TaskDetail(object):
-    """This class contains an entry that contains the persistance of a task
-    after or before (or during) it is running including any results it may have
-    produced, any state that it may be in (failed for example), any exception
-    that occured when running and any associated stacktrace that may have
-    occuring during that exception being thrown and any other metadata that
-    should be stored along-side the details about this task.
-
-    The data contained within this class need *not* backed by the backend
-    storage in real time. The data in this class will only be guaranteed to be
-    persisted when the logbook that contains this task detail is saved or when
-    the save() method is called directly.
-    """
-    def __init__(self, name, uuid, backend='memory'):
-        self._uuid = uuid
-        self._name = name
-        self.backend = backend
-        # TODO(harlowja): decide if these should be passed in and therefore
-        # immutable or let them be assigned?
-        #
-        # The state the task was last in.
-        self.state = None
-        # The results it may have produced (useful for reverting).
-        self.results = None
-        # An exception that it may have thrown (or part of it), useful for
-        # knowing what failed.
-        self.exception = None
-        # Any stack trace the exception may have had, useful for debugging or
-        # examining the failure in more depth.
-        self.stacktrace = None
-        # Any other metadata to include about this task while storing. For
-        # example timing information could be stored here, other misc. task
-        # related items.
-        self.meta = None
-        # The version of the task this task details was associated with which
-        # is quite useful for determining what versions of tasks this detail
-        # information can be associated with.
-        self.version = None
-
-    def save(self):
-        """Saves *most* of the components of this given object.
-
-        This will immediately and atomically save the attributes of this task
-        details object to a backing store providing by the backing api.
-
-        The underlying storage must contain an existing task details that this
-        save operation will merge with and then reflect those changes in this
-        object.
-        """
-        backend = self._get_backend()
-        if not backend:
-            raise NotImplementedError("No saving backend provided")
-        td_u = backend.taskdetails_save(self)
-        if td_u is self:
-            return
-        self.meta = td_u.meta
-        self.exception = td_u.exception
-        self.results = td_u.results
-        self.stacktrace = td_u.stacktrace
-        self.state = td_u.state
-
-    def _get_backend(self):
-        if not self.backend:
-            return None
-        return b_api.fetch(self.backend)
-
-    @property
-    def uuid(self):
-        return self._uuid
-
-    @property
-    def name(self):
-        return self._name
diff --git a/taskflow/persistence/utils.py b/taskflow/persistence/utils.py
new file mode 100644
index 000000000..8bd477ba1
--- /dev/null
+++ b/taskflow/persistence/utils.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import contextlib
+import logging
+
+from taskflow.openstack.common import uuidutils
+from taskflow.persistence import logbook
+
+LOG = logging.getLogger(__name__)
+
+
+def temporary_log_book(backend):
+    """Creates a temporary logbook for temporary usage in the given backend.
+
+    Mainly useful for tests and other use cases where a temporary logbook
+    is needed for a short-period of time.
+    """
+    book = logbook.LogBook('tmp')
+    with contextlib.closing(backend.get_connection()) as conn:
+        conn.save_logbook(book)
+        return book
+
+
+def temporary_flow_detail(backend):
+    """Creates a temporary flow detail and logbook for temporary usage in
+    the given backend.
+
+    Mainly useful for tests and other use cases where a temporary flow detail
+    is needed for a short-period of time.
+    """
+    flow_id = uuidutils.generate_uuid()
+    book = temporary_log_book(backend)
+    with contextlib.closing(backend.get_connection()) as conn:
+        book.add(logbook.FlowDetail(name='tmp-flow-detail', uuid=flow_id))
+        conn.save_logbook(book)
+        # Return the one from the saved logbook instead of the local one so
+        # that the freshest version is given back.
+        return (book, book.find(flow_id))
+
+
+def create_flow_detail(flow, book=None, backend=None):
+    """Creates a flow detail for the given flow and adds it to the provided
+    logbook (if provided) and then uses the given backend (if provided) to
+    save the logbook then returns the created flow detail.
+    """
+    try:
+        flow_name = getattr(flow, 'name')
+    except AttributeError:
+        LOG.warn("Flow %s does not have a name attribute, creating one.", flow)
+        flow_name = uuidutils.generate_uuid()
+    try:
+        flow_id = getattr(flow, 'uuid')
+    except AttributeError:
+        LOG.warn("Flow %s does not have a uuid attribute, creating one.", flow)
+        flow_id = uuidutils.generate_uuid()
+    flow_detail = logbook.FlowDetail(name=flow_name, uuid=flow_id)
+    if book is not None:
+        book.add(flow_detail)
+        if backend is not None:
+            with contextlib.closing(backend.get_connection()) as conn:
+                conn.save_logbook(book)
+        # Return the one from the saved logbook instead of the local one so
+        # that the freshest version is given back
+        return book.find(flow_id)
+    else:
+        if backend is not None:
+            LOG.warn("Can not save %s without a provided logbook", flow)
+        return flow_detail
diff --git a/taskflow/storage.py b/taskflow/storage.py
index 5b8acdf84..054e27106 100644
--- a/taskflow/storage.py
+++ b/taskflow/storage.py
@@ -16,32 +16,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import contextlib
+
 from taskflow import exceptions
 from taskflow.openstack.common import uuidutils
-from taskflow.persistence import flowdetail
 from taskflow.persistence import logbook
-from taskflow.persistence import taskdetail
 from taskflow import states
 from taskflow.utils import threading_utils
 
-
-def temporary_flow_detail():
-    """Creates flow detail class for temporary usage
-
-    Creates in-memory logbook and flow detail in it. Should
-    be useful for tests and other use cases where persistence
-    is not needed
-    """
-    lb = logbook.LogBook('tmp', backend='memory')
-    fd = flowdetail.FlowDetail(
-        name='tmp', uuid=uuidutils.generate_uuid(),
-        backend='memory')
-    lb.add(fd)
-    lb.save()
-    fd.save()
-    return fd
-
-
 STATES_WITH_RESULTS = (states.SUCCESS, states.REVERTING, states.FAILURE)
 
 
@@ -54,16 +36,17 @@ class Storage(object):
 
     injector_name = '_TaskFlow_INJECTOR'
 
-    def __init__(self, flow_detail=None):
+    def __init__(self, flow_detail, backend=None):
         self._result_mappings = {}
         self._reverse_mapping = {}
+        self._backend = backend
+        self._flowdetail = flow_detail
 
-        if flow_detail is None:
-            # TODO(imelnikov): this is useful mainly for tests;
-            #  maybe we should make flow_detail required parameter?
-            self._flowdetail = temporary_flow_detail()
-        else:
-            self._flowdetail = flow_detail
+    def _with_connection(self, functor, *args, **kwargs):
+        if self._backend is None:
+            return
+        with contextlib.closing(self._backend.get_connection()) as conn:
+            functor(conn, *args, **kwargs)
 
     def add_task(self, uuid, task_name):
         """Add the task to storage
@@ -72,12 +55,18 @@ class Storage(object):
         Task state is set to PENDING.
         """
         # TODO(imelnikov): check that task with same uuid or
-        #   task name does not exist
-        td = taskdetail.TaskDetail(name=task_name, uuid=uuid)
+        # task name does not exist
+        td = logbook.TaskDetail(name=task_name, uuid=uuid)
         td.state = states.PENDING
         self._flowdetail.add(td)
-        self._flowdetail.save()
-        td.save()
+        self._with_connection(self._save_flow_detail)
+        self._with_connection(self._save_task_detail, task_detail=td)
+
+    def _save_flow_detail(self, conn):
+        # NOTE(harlowja): we need to update our contained flow detail if
+        # the result of the update actually added more (aka another process
+        # added item to the flow detail).
+        self._flowdetail.update(conn.update_flow_details(self._flowdetail))
 
     def get_uuid_by_name(self, task_name):
         """Get uuid of task with given name"""
@@ -93,11 +82,17 @@ class Storage(object):
             raise exceptions.NotFound("Unknown task: %r" % uuid)
         return td
 
+    def _save_task_detail(self, conn, task_detail):
+        # NOTE(harlowja): we need to update our contained task detail if
+        # the result of the update actually added more (aka another process
+        # is also modifying the task detail).
+        task_detail.update(conn.update_task_details(task_detail))
+
     def set_task_state(self, uuid, state):
         """Set task state"""
         td = self._taskdetail_by_uuid(uuid)
         td.state = state
-        td.save()
+        self._with_connection(self._save_task_detail, task_detail=td)
 
     def get_task_state(self, uuid):
         """Get state of task with given uuid"""
@@ -108,7 +103,7 @@ class Storage(object):
         td = self._taskdetail_by_uuid(uuid)
         td.state = state
         td.results = data
-        td.save()
+        self._with_connection(self._save_task_detail, task_detail=td)
 
     def get(self, uuid):
         """Get result for task with id 'uuid' to storage"""
@@ -122,7 +117,7 @@ class Storage(object):
         td = self._taskdetail_by_uuid(uuid)
         td.results = None
         td.state = state
-        td.save()
+        self._with_connection(self._save_task_detail, task_detail=td)
 
     def inject(self, pairs):
         """Add values into storage
@@ -202,7 +197,7 @@ class Storage(object):
     def set_flow_state(self, state):
         """Set flowdetails state and save it"""
         self._flowdetail.state = state
-        self._flowdetail.save()
+        self._with_connection(self._save_flow_detail)
 
     def get_flow_state(self):
         """Set state from flowdetails"""
diff --git a/taskflow/test.py b/taskflow/test.py
index 63da745df..2f1ec49b9 100644
--- a/taskflow/test.py
+++ b/taskflow/test.py
@@ -18,38 +18,12 @@
 
 import unittest2
 
-from oslo.config import cfg
-
-CONF = cfg.CONF
-
 
 class TestCase(unittest2.TestCase):
     """Test case base class for all unit tests."""
 
     def setUp(self):
-        """Run before each test method to initialize test environment."""
         super(TestCase, self).setUp()
-        self.overriden = []
-        self.addCleanup(self._clear_attrs)
 
     def tearDown(self):
         super(TestCase, self).tearDown()
-        self._reset_flags()
-
-    def _reset_flags(self):
-        for k, group in self.overriden:
-            CONF.clear_override(k, group=group)
-
-    def _clear_attrs(self):
-        # Delete attributes that don't start with _ so they don't pin
-        # memory around unnecessarily for the duration of the test
-        # suite
-        for key in [k for k in self.__dict__.keys() if k[0] != '_']:
-            del self.__dict__[key]
-
-    def flags(self, **kw):
-        """Override flag variables for a test."""
-        group = kw.pop('group', None)
-        for k, v in kw.iteritems():
-            CONF.set_override(k, v, group)
-            self.overriden.append((k, group))
diff --git a/taskflow/tests/unit/persistence/base.py b/taskflow/tests/unit/persistence/base.py
index f5efdf8c9..f362f0c76 100644
--- a/taskflow/tests/unit/persistence/base.py
+++ b/taskflow/tests/unit/persistence/base.py
@@ -16,34 +16,33 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import contextlib
+
 from taskflow import exceptions as exc
 from taskflow.openstack.common import uuidutils
-from taskflow.persistence import flowdetail
 from taskflow.persistence import logbook
-from taskflow.persistence import taskdetail
 
 
 class PersistenceTestMixin(object):
-    def _get_backend():
+    def _get_connection():
         raise NotImplementedError()
 
-    def test_logbook_simple_save(self):
+    def test_logbook_save_retrieve(self):
         lb_id = uuidutils.generate_uuid()
         lb_meta = {'1': 2}
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
         lb.meta = lb_meta
 
         # Should not already exist
-        self.assertRaises(exc.NotFound, logbook.load, lb_id,
-                          backend=self._get_backend())
+        with contextlib.closing(self._get_connection()) as conn:
+            self.assertRaises(exc.NotFound, conn.get_logbook, lb_id)
+            conn.save_logbook(lb)
 
-        lb.save()
-        del lb
-        lb = None
-
-        lb = logbook.load(lb_id, backend=self._get_backend())
+        # Make sure we can reload it (and all of its attributes are what
+        # we expect them to be).
+        with contextlib.closing(self._get_connection()) as conn:
+            lb = conn.get_logbook(lb_id)
         self.assertEquals(lb_name, lb.name)
         self.assertEquals(0, len(lb))
         self.assertEquals(lb_meta, lb.meta)
@@ -53,109 +52,104 @@ class PersistenceTestMixin(object):
     def test_flow_detail_save(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        fd = flowdetail.FlowDetail('test', uuid=uuidutils.generate_uuid())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd = logbook.FlowDetail('test', uuid=uuidutils.generate_uuid())
         lb.add(fd)
 
         # Ensure we can't save it since its owning logbook hasn't been
-        # saved.
-        self.assertRaises(exc.NotFound, fd.save)
+        # saved (flow details can not exist on there own without a connection
+        # to a logbook).
+        with contextlib.closing(self._get_connection()) as conn:
+            self.assertRaises(exc.NotFound, conn.get_logbook, lb_id)
+            self.assertRaises(exc.NotFound, conn.update_flow_details, fd)
 
-        # Ok now we should be able to save it
-        lb.save()
-        fd.save()
+        # Ok now we should be able to save both.
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+            conn.update_flow_details(fd)
 
     def test_task_detail_save(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        fd = flowdetail.FlowDetail('test', uuid=uuidutils.generate_uuid())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd = logbook.FlowDetail('test', uuid=uuidutils.generate_uuid())
         lb.add(fd)
-        td = taskdetail.TaskDetail("detail-1", uuid=uuidutils.generate_uuid())
+        td = logbook.TaskDetail("detail-1", uuid=uuidutils.generate_uuid())
         fd.add(td)
 
         # Ensure we can't save it since its owning logbook hasn't been
-        # saved.
-        self.assertRaises(exc.NotFound, fd.save)
-        self.assertRaises(exc.NotFound, td.save)
+        # saved (flow details/task details can not exist on there own without
+        # there parent existing).
+        with contextlib.closing(self._get_connection()) as conn:
+            self.assertRaises(exc.NotFound, conn.update_flow_details, fd)
+            self.assertRaises(exc.NotFound, conn.update_task_details, td)
 
-        # Ok now we should be able to save it
-        lb.save()
-        fd.save()
-        td.save()
+        # Ok now we should be able to save them.
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+            conn.update_flow_details(fd)
+            conn.update_task_details(td)
 
     def test_logbook_merge_flow_detail(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        fd = flowdetail.FlowDetail('test', uuid=uuidutils.generate_uuid())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd = logbook.FlowDetail('test', uuid=uuidutils.generate_uuid())
         lb.add(fd)
-        lb.save()
-
-        lb2 = logbook.LogBook(name=lb_name, uuid=lb_id,
-                              backend=self._get_backend())
-        fd = flowdetail.FlowDetail('test2', uuid=uuidutils.generate_uuid())
-        lb2.add(fd)
-        lb2.save()
-
-        lb3 = logbook.load(lb_id, backend=self._get_backend())
-        self.assertEquals(2, len(lb3))
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+        lb2 = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd2 = logbook.FlowDetail('test2', uuid=uuidutils.generate_uuid())
+        lb2.add(fd2)
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb2)
+        with contextlib.closing(self._get_connection()) as conn:
+            lb3 = conn.get_logbook(lb_id)
+            self.assertEquals(2, len(lb3))
 
     def test_logbook_add_flow_detail(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        fd = flowdetail.FlowDetail('test', uuid=uuidutils.generate_uuid())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd = logbook.FlowDetail('test', uuid=uuidutils.generate_uuid())
         lb.add(fd)
-        lb.save()
-
-        lb2 = logbook.load(lb_id, backend=self._get_backend())
-        self.assertEquals(1, len(lb2))
-        self.assertEquals(1, len(lb))
-
-        self.assertEquals(fd.name, lb2.find(fd.uuid).name)
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+        with contextlib.closing(self._get_connection()) as conn:
+            lb2 = conn.get_logbook(lb_id)
+            self.assertEquals(1, len(lb2))
+            self.assertEquals(1, len(lb))
+            self.assertEquals(fd.name, lb2.find(fd.uuid).name)
 
     def test_logbook_add_task_detail(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        fd = flowdetail.FlowDetail('test', uuid=uuidutils.generate_uuid())
-        td = taskdetail.TaskDetail("detail-1", uuid=uuidutils.generate_uuid())
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        fd = logbook.FlowDetail('test', uuid=uuidutils.generate_uuid())
+        td = logbook.TaskDetail("detail-1", uuid=uuidutils.generate_uuid())
         fd.add(td)
         lb.add(fd)
-        lb.save()
-
-        lb2 = logbook.load(lb_id, backend=self._get_backend())
-        self.assertEquals(1, len(lb2))
-        tasks = 0
-        for fd in lb:
-            tasks += len(fd)
-        self.assertEquals(1, tasks)
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+        with contextlib.closing(self._get_connection()) as conn:
+            lb2 = conn.get_logbook(lb_id)
+            self.assertEquals(1, len(lb2))
+            tasks = 0
+            for fd in lb:
+                tasks += len(fd)
+            self.assertEquals(1, tasks)
 
     def test_logbook_delete(self):
         lb_id = uuidutils.generate_uuid()
         lb_name = 'lb-%s' % (lb_id)
-        lb = logbook.LogBook(name=lb_name, uuid=lb_id,
-                             backend=self._get_backend())
-
-        # Ensure we can't delete it since it hasn't been saved
-        self.assertRaises(exc.NotFound, lb.delete)
-
-        lb.save()
-
-        lb2 = logbook.load(lb_id, backend=self._get_backend())
-        self.assertIsNotNone(lb2)
-
-        lb.delete()
-
-        self.assertRaises(exc.NotFound, lb.delete)
+        lb = logbook.LogBook(name=lb_name, uuid=lb_id)
+        with contextlib.closing(self._get_connection()) as conn:
+            self.assertRaises(exc.NotFound, conn.destroy_logbook, lb_id)
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.save_logbook(lb)
+        with contextlib.closing(self._get_connection()) as conn:
+            lb2 = conn.get_logbook(lb_id)
+            self.assertIsNotNone(lb2)
+        with contextlib.closing(self._get_connection()) as conn:
+            conn.destroy_logbook(lb_id)
+            self.assertRaises(exc.NotFound, conn.destroy_logbook, lb_id)
diff --git a/taskflow/tests/unit/persistence/test_memory_persistence.py b/taskflow/tests/unit/persistence/test_memory_persistence.py
index 0d940b356..da088c13f 100644
--- a/taskflow/tests/unit/persistence/test_memory_persistence.py
+++ b/taskflow/tests/unit/persistence/test_memory_persistence.py
@@ -16,15 +16,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from taskflow.persistence.backends import api as b_api
+from taskflow.persistence.backends import impl_memory
 from taskflow import test
 from taskflow.tests.unit.persistence import base
 
 
 class MemoryPersistenceTest(test.TestCase, base.PersistenceTestMixin):
-    def _get_backend(self):
-        return 'memory'
+    def _get_connection(self):
+        return impl_memory.MemoryBackend({}).get_connection()
 
     def tearDown(self):
-        b_api.fetch(self._get_backend()).clear_all()
+        conn = self._get_connection()
+        conn.clear_all()
         super(MemoryPersistenceTest, self).tearDown()
diff --git a/taskflow/tests/unit/persistence/test_sql_persistence.py b/taskflow/tests/unit/persistence/test_sql_persistence.py
index 44a7b0cf0..ba60f5a97 100644
--- a/taskflow/tests/unit/persistence/test_sql_persistence.py
+++ b/taskflow/tests/unit/persistence/test_sql_persistence.py
@@ -19,31 +19,29 @@
 import os
 import tempfile
 
-from taskflow.openstack.common.db.sqlalchemy import session
-from taskflow.persistence.backends import api as b_api
-from taskflow.persistence.backends.sqlalchemy import migration
+from taskflow.persistence.backends import impl_sqlalchemy
 from taskflow import test
 from taskflow.tests.unit.persistence import base
 
 
 class SqlPersistenceTest(test.TestCase, base.PersistenceTestMixin):
     """Inherits from the base test and sets up a sqlite temporary db."""
-    def _get_backend(self):
-        return 'sqlalchemy'
-
-    def setupDatabase(self):
-        _handle, db_location = tempfile.mkstemp()
-        db_uri = "sqlite:///%s" % (db_location)
-        session.set_defaults(db_uri, db_location)
-        migration.db_sync()
-        return db_location
+    def _get_connection(self):
+        conf = {
+            'connection': self.db_uri,
+        }
+        conn = impl_sqlalchemy.SQLAlchemyBackend(conf).get_connection()
+        return conn
 
     def setUp(self):
         super(SqlPersistenceTest, self).setUp()
-        self.db_location = self.setupDatabase()
+        self.db_location = tempfile.mktemp(suffix='.db')
+        self.db_uri = "sqlite:///%s" % (self.db_location)
+        # Ensure upgraded to the right schema
+        conn = self._get_connection()
+        conn.upgrade()
 
     def tearDown(self):
-        b_api.fetch(self._get_backend()).clear_all()
         super(SqlPersistenceTest, self).tearDown()
         if self.db_location and os.path.isfile(self.db_location):
             os.unlink(self.db_location)
diff --git a/taskflow/tests/unit/test_action_engine.py b/taskflow/tests/unit/test_action_engine.py
index 0a3eb6eda..1314c9edc 100644
--- a/taskflow/tests/unit/test_action_engine.py
+++ b/taskflow/tests/unit/test_action_engine.py
@@ -16,21 +16,22 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import contextlib
 from multiprocessing import pool
 import time
 
 from taskflow.patterns import linear_flow as lf
 from taskflow.patterns import unordered_flow as uf
 
+from taskflow.engines.action_engine import engine as eng
 from taskflow import exceptions
-from taskflow.persistence import taskdetail
+from taskflow.persistence.backends import impl_memory
+from taskflow.persistence import logbook
+from taskflow.persistence import utils as p_utils
 from taskflow import states
-from taskflow import storage
 from taskflow import task
 from taskflow import test
 
-from taskflow.engines.action_engine import engine as eng
-
 
 class TestTask(task.Task):
 
@@ -103,8 +104,17 @@ class EngineTestBase(object):
     def setUp(self):
         super(EngineTestBase, self).setUp()
         self.values = []
+        self.backend = impl_memory.MemoryBackend(conf={})
+        self.book = p_utils.temporary_log_book(self.backend)
 
-    def _make_engine(self, _flow, _flow_detail=None):
+    def tearDown(self):
+        super(EngineTestBase, self).tearDown()
+        with contextlib.closing(self.backend) as be:
+            with contextlib.closing(be.get_connection()) as conn:
+                conn.clear_all()
+        self.book = None
+
+    def _make_engine(self, flow, flow_detail=None):
         raise NotImplementedError()
 
 
@@ -114,7 +124,6 @@ class EngineTaskTest(EngineTestBase):
         flow = lf.Flow('test-1')
         flow.add(TestTask(self.values, name='task1'))
         engine = self._make_engine(flow)
-        engine.compile()
         engine.run()
         self.assertEquals(self.values, ['task1'])
 
@@ -405,13 +414,15 @@ class EngineParallelFlowTest(EngineTestBase):
         )
 
         # Create FlowDetail as if we already run task1
-        fd = storage.temporary_flow_detail()
-        td = taskdetail.TaskDetail(name='task1', uuid='42')
+        _lb, fd = p_utils.temporary_flow_detail(self.backend)
+        td = logbook.TaskDetail(name='task1', uuid='42')
         td.state = states.SUCCESS
         td.results = 17
         fd.add(td)
-        fd.save()
-        td.save()
+
+        with contextlib.closing(self.backend.get_connection()) as conn:
+            fd.update(conn.update_flow_details(fd))
+            td.update(conn.update_task_details(td))
 
         engine = self._make_engine(flow, fd)
         engine.run()
@@ -425,22 +436,30 @@ class SingleThreadedEngineTest(EngineTaskTest,
                                EngineParallelFlowTest,
                                test.TestCase):
     def _make_engine(self, flow, flow_detail=None):
-        return eng.SingleThreadedActionEngine(flow, flow_detail=flow_detail)
+        if flow_detail is None:
+            flow_detail = p_utils.create_flow_detail(flow, self.book,
+                                                     self.backend)
+        return eng.SingleThreadedActionEngine(flow, backend=self.backend,
+                                              flow_detail=flow_detail)
 
 
 class MultiThreadedEngineTest(EngineTaskTest,
                               EngineLinearFlowTest,
                               EngineParallelFlowTest,
                               test.TestCase):
-
-    def _make_engine(self, flow, flow_detail=None):
-        return eng.MultiThreadedActionEngine(flow, flow_detail=flow_detail)
+    def _make_engine(self, flow, flow_detail=None, thread_pool=None):
+        if flow_detail is None:
+            flow_detail = p_utils.create_flow_detail(flow, self.book,
+                                                     self.backend)
+        return eng.MultiThreadedActionEngine(flow, backend=self.backend,
+                                             flow_detail=flow_detail,
+                                             thread_pool=thread_pool)
 
     def test_using_common_pool(self):
         flow = TestTask(self.values, name='task1')
         thread_pool = pool.ThreadPool()
-        e1 = eng.MultiThreadedActionEngine(flow, thread_pool=thread_pool)
-        e2 = eng.MultiThreadedActionEngine(flow, thread_pool=thread_pool)
+        e1 = self._make_engine(flow, thread_pool=thread_pool)
+        e2 = self._make_engine(flow, thread_pool=thread_pool)
         self.assertIs(e1.thread_pool, e2.thread_pool)
 
     def test_parallel_revert_specific(self):
diff --git a/taskflow/tests/unit/test_decorators.py b/taskflow/tests/unit/test_decorators.py
index 037ab2b50..06a9338d3 100644
--- a/taskflow/tests/unit/test_decorators.py
+++ b/taskflow/tests/unit/test_decorators.py
@@ -23,13 +23,11 @@ from taskflow import test
 from taskflow.engines.action_engine import engine as eng
 
 
-def _make_engine(flow):
-    e = eng.SingleThreadedActionEngine(flow)
-    e.compile()
-    return e
-
-
 class WrapableObjectsTest(test.TestCase):
+    def _make_engine(self, flow):
+        e = eng.SingleThreadedActionEngine(flow)
+        e.compile()
+        return e
 
     def test_simple_function(self):
         values = []
@@ -52,7 +50,7 @@ class WrapableObjectsTest(test.TestCase):
             run_fail
         )
         with self.assertRaisesRegexp(RuntimeError, '^Woot'):
-            e = _make_engine(flow)
+            e = self._make_engine(flow)
             e.run()
         self.assertEquals(values, ['one', 'fail', 'revert one'])
 
@@ -80,7 +78,7 @@ class WrapableObjectsTest(test.TestCase):
             tasks.run_fail
         )
         with self.assertRaisesRegexp(RuntimeError, '^Woot'):
-            e = _make_engine(flow)
+            e = self._make_engine(flow)
             e.run()
         self.assertEquals(tasks.values, ['one', 'fail'])
 
@@ -106,7 +104,7 @@ class WrapableObjectsTest(test.TestCase):
             MyTasks.run_fail
         )
         with self.assertRaisesRegexp(RuntimeError, '^Woot'):
-            e = _make_engine(flow)
+            e = self._make_engine(flow)
             e.run()
         self.assertEquals(values, ['one', 'fail'])
 
@@ -133,6 +131,6 @@ class WrapableObjectsTest(test.TestCase):
             MyTasks.run_fail
         )
         with self.assertRaisesRegexp(RuntimeError, '^Woot'):
-            e = _make_engine(flow)
+            e = self._make_engine(flow)
             e.run()
         self.assertEquals(MyTasks.values, ['one', 'fail'])
diff --git a/taskflow/tests/unit/test_linear_flow.py b/taskflow/tests/unit/test_linear_flow.py
index 21715e36b..f0645cc4b 100644
--- a/taskflow/tests/unit/test_linear_flow.py
+++ b/taskflow/tests/unit/test_linear_flow.py
@@ -19,24 +19,22 @@
 import collections
 
 from taskflow import decorators
+from taskflow.engines.action_engine import engine as eng
 from taskflow import exceptions as exc
+from taskflow.patterns import linear_flow as lw
 from taskflow import states
 from taskflow import test
 
-from taskflow.patterns import linear_flow as lw
 from taskflow.tests import utils
 
-from taskflow.engines.action_engine import engine as eng
-
-
-def _make_engine(flow):
-    e = eng.SingleThreadedActionEngine(flow)
-    e.compile()
-    e.storage.inject([('context', {})])
-    return e
-
 
 class LinearFlowTest(test.TestCase):
+    def _make_engine(self, flow):
+        e = eng.SingleThreadedActionEngine(flow)
+        e.compile()
+        e.storage.inject([('context', {})])
+        return e
+
     def make_reverting_task(self, token, blowup=False):
 
         def do_revert(context, *args, **kwargs):
@@ -67,7 +65,7 @@ class LinearFlowTest(test.TestCase):
         wf = lw.Flow("the-test-action")
         wf.add(do_apply1)
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.run()
         data = e.storage.fetch_all()
         self.assertIn('a', data)
@@ -92,7 +90,7 @@ class LinearFlowTest(test.TestCase):
         wf.add(do_apply1)
         wf.add(do_apply2)
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.run()
         self.assertEquals(2, len(e.storage.fetch('context')))
 
@@ -111,7 +109,7 @@ class LinearFlowTest(test.TestCase):
         wf.add(self.make_reverting_task(2, False))
         wf.add(self.make_reverting_task(1, True))
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.notifier.register('*', listener)
         e.task_notifier.register('*', task_listener)
         self.assertRaises(Exception, e.run)
@@ -148,7 +146,7 @@ class LinearFlowTest(test.TestCase):
         wf = lw.Flow("the-test-action")
         wf.add(self.make_reverting_task(1))
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.notifier.register('*', listener)
         e.run()
 
@@ -159,7 +157,7 @@ class LinearFlowTest(test.TestCase):
         for i in range(0, 10):
             wf.add(self.make_reverting_task(i))
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         capture_func, captured = self._capture_states()
         e.task_notifier.register('*', capture_func)
         e.run()
@@ -189,7 +187,7 @@ class LinearFlowTest(test.TestCase):
         wf.add(self.make_reverting_task(2, True))
 
         capture_func, captured = self._capture_states()
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.task_notifier.register('*', capture_func)
 
         self.assertRaises(Exception, e.run)
@@ -225,7 +223,7 @@ class LinearFlowTest(test.TestCase):
         wf = lw.Flow("the-test-action")
         wf.add(task_a)
         wf.add(task_b)
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         self.assertRaises(exc.NotFound, e.run)
 
     def test_flow_bad_order(self):
@@ -239,7 +237,7 @@ class LinearFlowTest(test.TestCase):
         no_req_task = utils.ProvidesRequiresTask('test-2', requires=['c'],
                                                  provides=[])
         wf.add(no_req_task)
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         self.assertRaises(exc.NotFound, e.run)
 
     def test_flow_set_order(self):
@@ -250,7 +248,7 @@ class LinearFlowTest(test.TestCase):
         wf.add(utils.ProvidesRequiresTask('test-2',
                                           requires=set(['a', 'b']),
                                           provides=set([])))
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.run()
         run_context = e.storage.fetch('context')
         ordering = run_context[utils.ORDER_KEY]
@@ -283,7 +281,7 @@ class LinearFlowTest(test.TestCase):
                                           requires=['d'],
                                           provides=[]))
 
-        e = _make_engine(wf)
+        e = self._make_engine(wf)
         e.run()
         run_context = e.storage.fetch('context')
         ordering = run_context[utils.ORDER_KEY]
diff --git a/taskflow/tests/unit/test_storage.py b/taskflow/tests/unit/test_storage.py
index b0cf0e537..8e7ed3d65 100644
--- a/taskflow/tests/unit/test_storage.py
+++ b/taskflow/tests/unit/test_storage.py
@@ -16,21 +16,38 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import contextlib
+
 from taskflow import exceptions
+from taskflow.persistence.backends import impl_memory
+from taskflow.persistence import utils as p_utils
 from taskflow import states
 from taskflow import storage
 from taskflow import test
 
 
 class StorageTest(test.TestCase):
+    def setUp(self):
+        super(StorageTest, self).setUp()
+        self.backend = impl_memory.MemoryBackend(conf={})
+
+    def _get_storage(self):
+        lb, flow_detail = p_utils.temporary_flow_detail(self.backend)
+        return storage.Storage(backend=self.backend, flow_detail=flow_detail)
+
+    def tearDown(self):
+        super(StorageTest, self).tearDown()
+        with contextlib.closing(self.backend) as be:
+            with contextlib.closing(be.get_connection()) as conn:
+                conn.clear_all()
 
     def test_add_task(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         self.assertEquals(s.get_task_state('42'), states.PENDING)
 
     def test_save_and_get(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         s.save('42', 5)
         self.assertEquals(s.get('42'), 5)
@@ -38,20 +55,20 @@ class StorageTest(test.TestCase):
         self.assertEquals(s.get_task_state('42'), states.SUCCESS)
 
     def test_save_and_get_other_state(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         s.save('42', 5, states.FAILURE)
         self.assertEquals(s.get('42'), 5)
         self.assertEquals(s.get_task_state('42'), states.FAILURE)
 
     def test_get_non_existing_var(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         with self.assertRaises(exceptions.NotFound):
             s.get('42')
 
     def test_reset(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         s.save('42', 5)
         s.reset('42')
@@ -60,12 +77,12 @@ class StorageTest(test.TestCase):
             s.get('42')
 
     def test_reset_unknown_task(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         self.assertEquals(s.reset('42'), None)
 
     def test_fetch_by_name(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         name = 'my result'
         s.set_result_mapping('42', {name: None})
@@ -74,13 +91,13 @@ class StorageTest(test.TestCase):
         self.assertEquals(s.fetch_all(), {name: 5})
 
     def test_fetch_unknown_name(self):
-        s = storage.Storage()
+        s = self._get_storage()
         with self.assertRaisesRegexp(exceptions.NotFound,
                                      "^Name 'xxx' is not mapped"):
             s.fetch('xxx')
 
     def test_fetch_result_not_ready(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         name = 'my result'
         s.set_result_mapping('42', {name: None})
@@ -89,7 +106,7 @@ class StorageTest(test.TestCase):
         self.assertEquals(s.fetch_all(), {})
 
     def test_save_multiple_results(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         s.set_result_mapping('42', {'foo': 0, 'bar': 1, 'whole': None})
         s.save('42', ('spam', 'eggs'))
@@ -100,14 +117,14 @@ class StorageTest(test.TestCase):
         })
 
     def test_mapping_none(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         s.set_result_mapping('42', None)
         s.save('42', 5)
         self.assertEquals(s.fetch_all(), {})
 
     def test_inject(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.inject({'foo': 'bar', 'spam': 'eggs'})
         self.assertEquals(s.fetch('spam'), 'eggs')
         self.assertEquals(s.fetch_all(), {
@@ -116,48 +133,49 @@ class StorageTest(test.TestCase):
         })
 
     def test_fetch_meapped_args(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.inject({'foo': 'bar', 'spam': 'eggs'})
         self.assertEquals(s.fetch_mapped_args({'viking': 'spam'}),
                           {'viking': 'eggs'})
 
     def test_fetch_not_found_args(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.inject({'foo': 'bar', 'spam': 'eggs'})
         with self.assertRaises(exceptions.NotFound):
             s.fetch_mapped_args({'viking': 'helmet'})
 
     def test_set_and_get_task_state(self):
-        s = storage.Storage()
+        s = self._get_storage()
         state = states.PENDING
         s.add_task('42', 'my task')
         s.set_task_state('42', state)
         self.assertEquals(s.get_task_state('42'), state)
 
     def test_get_state_of_unknown_task(self):
-        s = storage.Storage()
+        s = self._get_storage()
         with self.assertRaisesRegexp(exceptions.NotFound, '^Unknown'):
             s.get_task_state('42')
 
     def test_task_by_name(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.add_task('42', 'my task')
         self.assertEquals(s.get_uuid_by_name('my task'), '42')
 
     def test_unknown_task_by_name(self):
-        s = storage.Storage()
+        s = self._get_storage()
         with self.assertRaisesRegexp(exceptions.NotFound,
                                      '^Unknown task name:'):
             s.get_uuid_by_name('42')
 
     def test_get_flow_state(self):
-        fd = storage.temporary_flow_detail()
+        lb, fd = p_utils.temporary_flow_detail(backend=self.backend)
         fd.state = states.INTERRUPTED
-        fd.save()
-        s = storage.Storage(fd)
+        with contextlib.closing(self.backend.get_connection()) as conn:
+            fd.update(conn.update_flow_details(fd))
+        s = storage.Storage(flow_detail=fd, backend=self.backend)
         self.assertEquals(s.get_flow_state(), states.INTERRUPTED)
 
     def test_set_and_get_flow_state(self):
-        s = storage.Storage()
+        s = self._get_storage()
         s.set_flow_state(states.SUCCESS)
         self.assertEquals(s.get_flow_state(), states.SUCCESS)
diff --git a/taskflow/utils/misc.py b/taskflow/utils/misc.py
index 00496bbd2..f536d450b 100644
--- a/taskflow/utils/misc.py
+++ b/taskflow/utils/misc.py
@@ -38,6 +38,49 @@ def get_task_version(task):
     return task_version
 
 
+class ExponentialBackoff(object):
+    def __init__(self, attempts, exponent=2):
+        self.attempts = int(attempts)
+        self.exponent = exponent
+
+    def __iter__(self):
+        if self.attempts <= 0:
+            raise StopIteration()
+        for i in xrange(0, self.attempts):
+            yield self.exponent ** i
+
+    def __str__(self):
+        return "ExponentialBackoff: %s" % ([str(v) for v in self])
+
+
+def as_bool(val):
+    if isinstance(val, bool):
+        return val
+    if isinstance(val, basestring):
+        if val.lower() in ('f', 'false', '0', 'n', 'no'):
+            return False
+        if val.lower() in ('t', 'true', '1', 'y', 'yes'):
+            return True
+    return bool(val)
+
+
+def as_int(obj, quiet=False):
+    # Try "2" -> 2
+    try:
+        return int(obj)
+    except (ValueError, TypeError):
+        pass
+    # Try "2.5" -> 2
+    try:
+        return int(float(obj))
+    except (ValueError, TypeError):
+        pass
+    # Eck, not sure what this is then.
+    if not quiet:
+        raise TypeError("Can not translate %s to an integer." % (obj))
+    return obj
+
+
 def is_version_compatible(version_1, version_2):
     """Checks for major version compatibility of two *string" versions."""
     try:
diff --git a/tools/pip-requires b/tools/pip-requires
index 3f7082a9c..4018c4cc9 100644
--- a/tools/pip-requires
+++ b/tools/pip-requires
@@ -15,3 +15,5 @@ alembic>=0.4.1
 networkx>=1.8.1
 threading2
 Babel>=0.9.6
+# Used for backend storage engine loading
+stevedore>=0.10