diff --git a/bigchaindb/__init__.py b/bigchaindb/__init__.py index 073b1ce9..8dc0318a 100644 --- a/bigchaindb/__init__.py +++ b/bigchaindb/__init__.py @@ -15,6 +15,7 @@ config = { 'threads': None, # if none, the value will be cpu_count * 2 + 1 }, 'database': { + 'backend': 'rethinkdb', 'host': os.environ.get('BIGCHAINDB_DATABASE_HOST', 'localhost'), 'port': 28015, 'name': 'bigchain', diff --git a/bigchaindb/backend/__init__.py b/bigchaindb/backend/__init__.py index e69de29b..1b000464 100644 --- a/bigchaindb/backend/__init__.py +++ b/bigchaindb/backend/__init__.py @@ -0,0 +1 @@ +from bigchaindb.backend.connection import connect # noqa diff --git a/bigchaindb/backend/connection.py b/bigchaindb/backend/connection.py index e69de29b..70852268 100644 --- a/bigchaindb/backend/connection.py +++ b/bigchaindb/backend/connection.py @@ -0,0 +1,15 @@ +from importlib import import_module + +BACKENDS = { + 'rethinkdb': 'bigchaindb.backend.rethinkdb.connection.RethinkDBConnection' +} + + +def connect(backend, host, port, dbname): + module_name, _, class_name = BACKENDS[backend].rpartition('.') + Class = getattr(import_module(module_name), class_name) + return Class(host, port, dbname) + + +class Connection: + pass diff --git a/bigchaindb/backend/rethinkdb/connection.py b/bigchaindb/backend/rethinkdb/connection.py index e69de29b..de0ea79a 100644 --- a/bigchaindb/backend/rethinkdb/connection.py +++ b/bigchaindb/backend/rethinkdb/connection.py @@ -0,0 +1,64 @@ +import time +import logging + +import rethinkdb as r + +import bigchaindb +from bigchaindb.backend.connection import Connection + +logger = logging.getLogger(__name__) + + +class RethinkDBConnection(Connection): + """This class is a proxy to run queries against the database, + it is: + - lazy, since it creates a connection only when needed + - resilient, because before raising exceptions it tries + more times to run the query or open a connection. + """ + + def __init__(self, host=None, port=None, db=None, max_tries=3): + """Create a new Connection instance. + + Args: + host (str, optional): the host to connect to. + port (int, optional): the port to connect to. + db (str, optional): the database to use. + max_tries (int, optional): how many tries before giving up. + """ + + self.host = host or bigchaindb.config['database']['host'] + self.port = port or bigchaindb.config['database']['port'] + self.db = db or bigchaindb.config['database']['name'] + self.max_tries = max_tries + self.conn = None + + def run(self, query): + """Run a query. + + Args: + query: the RethinkDB query. + """ + + if self.conn is None: + self._connect() + + for i in range(self.max_tries): + try: + return query.run(self.conn) + except r.ReqlDriverError as exc: + if i + 1 == self.max_tries: + raise + else: + self._connect() + + def _connect(self): + for i in range(self.max_tries): + try: + self.conn = r.connect(host=self.host, port=self.port, + db=self.db) + except r.ReqlDriverError as exc: + if i + 1 == self.max_tries: + raise + else: + time.sleep(2**i) diff --git a/tests/backend/test_connection.py b/tests/backend/test_connection.py new file mode 100644 index 00000000..6fb6478d --- /dev/null +++ b/tests/backend/test_connection.py @@ -0,0 +1,15 @@ +def test_get_connection_returns_the_correct_instance(): + from bigchaindb.backend import connect + from bigchaindb.backend.connection import Connection + from bigchaindb.backend.rethinkdb.connection import RethinkDBConnection + + config = { + 'backend': 'rethinkdb', + 'host': 'localhost', + 'port': 28015, + 'dbname': 'test' + } + + conn = connect(**config) + assert isinstance(conn, Connection) + assert isinstance(conn, RethinkDBConnection)