Esempio n. 1
0
    async def health(request):
        """Get hive health data. 500 if behind by more than 3 blocks."""
        #pylint: disable=unused-argument
        is_syncer = Conf.get('sync_to_s3')
        max_head_age = (Conf.get('trail_blocks') + 3) * 3
        state = await _head_state()

        if not state:
            status = 500
            result = 'db not available'
        elif not is_syncer and state['db_head_age'] > max_head_age:
            status = 500
            result = 'head block age (%s) > max (%s); head block num: %s' % (
                state['db_head_age'], max_head_age, state['db_head_block'])
        else:
            status = 200
            result = 'head block age is %d, head block num is %d' % (
                state['db_head_age'], state['db_head_block'])

        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      sync_service=is_syncer,
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))
Esempio n. 2
0
 def instance(cls):
     """Get a singleton, lazily initialized"""
     if not cls._instance:
         cls._instance = SteemClient(url=Conf.get('steemd_url'),
                                     max_batch=Conf.get('max_batch'),
                                     max_workers=Conf.get('max_workers'))
     return cls._instance
Esempio n. 3
0
def run():
    Conf.init_argparse()
    mode = '/'.join(Conf.get('mode'))

    if mode == 'server':
        run_server()

    elif mode == 'sync':
        run_sync()

    elif mode == 'status':
        print(DbState.status())

    else:
        raise Exception("unknown run mode %s" % mode)
Esempio n. 4
0
    def run(cls):
        """Initialize state; setup/recovery checks; sync and runloop."""

        # ensure db schema up to date, check app status
        DbState.initialize()

        # prefetch id->name memory map
        Accounts.load_ids()

        if DbState.is_initial_sync():
            # resume initial sync
            cls.initial()
            DbState.finish_initial_sync()

        else:
            # recover from fork
            Blocks.verify_head()

            # perform cleanup if process did not exit cleanly
            CachedPost.recover_missing_posts()

        # debug mode: no sync, just stream
        if Conf.get('disable_sync'):
            return cls.listen()

        while True:
            # sync up to irreversible block
            cls.from_steemd()

            # take care of payout backlog
            CachedPost.dirty_paidouts(Blocks.head_date())
            CachedPost.flush(trx=True)

            # listen for new blocks
            cls.listen()
Esempio n. 5
0
 def create_engine(echo=False):
     engine = sqlalchemy.create_engine(
         Conf.get('database_url'),
         isolation_level="READ UNCOMMITTED",  # only works in mysql
         pool_recycle=3600,
         echo=echo)
     return engine
Esempio n. 6
0
    def listen(cls):
        trail_blocks = Conf.get('trail_blocks')
        assert trail_blocks >= 0
        assert trail_blocks < 25

        steemd = SteemClient.instance()
        hive_head = Blocks.head_num()
        for block in steemd.stream_blocks(hive_head + 1, trail_blocks, max_gap=40):
            start_time = time.perf_counter()

            query("START TRANSACTION")
            num = Blocks.process(block)
            follows = Follow.flush(trx=False)
            accts = Accounts.flush(trx=False, period=8)
            CachedPost.dirty_paidouts(block['timestamp'])
            cnt = CachedPost.flush(trx=False)
            query("COMMIT")

            ms = (time.perf_counter() - start_time) * 1000
            print("[LIVE] Got block %d at %s --% 4d txs,% 3d posts,% 3d edits,"
                  "% 3d payouts,% 3d votes,% 3d accounts,% 3d follows --% 5dms%s"
                  % (num, block['timestamp'], len(block['transactions']),
                     cnt['insert'], cnt['update'], cnt['payout'], cnt['upvote'],
                     accts, follows, int(ms), ' SLOW' if ms > 1000 else ''))

            # once per hour, update accounts
            if num % 1200 == 0:
                Accounts.dirty_oldest(10000)
                Accounts.flush(trx=True)
                #Accounts.update_ranks()

            # once a minute, update chain props
            if num % 20 == 0:
                cls._update_chain_state(steemd)
Esempio n. 7
0
def run():
    """Run the proper routine as indicated by hive --mode argument."""

    conf = Conf.init_argparse()
    Db.set_shared_instance(conf.db())
    mode = conf.mode()

    if mode == 'server':
        from hive.server.serve import run_server
        run_server(conf=conf)

    elif mode == 'sync':
        from hive.indexer.sync import Sync
        Sync(conf=conf).run()

    elif mode == 'status':
        from hive.db.db_state import DbState
        print(DbState.status())

    #elif mode == 'sync-profile':
    #    from hive.indexer.sync import Sync
    #    from hive.utils.profiler import Profiler
    #    with Profiler():
    #        Sync(conf=conf).run()

    else:
        raise Exception("unknown run mode %s" % mode)
Esempio n. 8
0
 def create_engine(echo=False):
     """Create a new SA db engine. Use echo=True for ultra verbose."""
     engine = sqlalchemy.create_engine(
         Conf.get('database_url'),
         isolation_level="READ UNCOMMITTED", # only works in mysql
         pool_recycle=3600,
         echo=echo)
     return engine
Esempio n. 9
0
def run():
    """Run the proper routine as indicated by hive --mode argument."""

    Conf.init_argparse()
    mode = Conf.run_mode()

    if mode == 'server':
        run_server()

    elif mode == 'sync':
        Sync.run()

    elif mode == 'status':
        print(DbState.status())

    else:
        raise Exception("unknown run mode %s" % mode)
Esempio n. 10
0
    def listen(cls):
        """Live (block following) mode."""
        trail_blocks = Conf.get('trail_blocks')
        assert trail_blocks >= 0
        assert trail_blocks <= 100

        # debug: no max gap if disable_sync in effect
        max_gap = None if Conf.get('disable_sync') else 100

        steemd = SteemClient.instance()
        hive_head = Blocks.head_num()

        for block in steemd.stream_blocks(hive_head + 1, trail_blocks,
                                          max_gap):
            start_time = perf()

            query("START TRANSACTION")
            num = Blocks.process(block)
            follows = Follow.flush(trx=False)
            accts = Accounts.flush(trx=False, spread=8)
            CachedPost.dirty_paidouts(block['timestamp'])
            cnt = CachedPost.flush(trx=False)
            query("COMMIT")

            ms = (perf() - start_time) * 1000
            log.info(
                "[LIVE] Got block %d at %s --% 4d txs,% 3d posts,% 3d edits,"
                "% 3d payouts,% 3d votes,% 3d accts,% 3d follows --% 5dms%s",
                num, block['timestamp'], len(block['transactions']),
                cnt['insert'], cnt['update'], cnt['payout'], cnt['upvote'],
                accts, follows, int(ms), ' SLOW' if ms > 1000 else '')

            # once per hour, update accounts
            if num % 1200 == 0:
                Accounts.dirty_oldest(10000)
                Accounts.flush(trx=True)
                #Accounts.update_ranks()

            # once a minute, update chain props
            if num % 20 == 0:
                cls._update_chain_state(steemd)
Esempio n. 11
0
def run():
    """Run the service specified in the `--mode` argument."""

    conf = Conf.init_argparse()
    Db.set_shared_instance(conf.db())
    mode = conf.mode()

    if conf.get('test_profile'):
        from hive.utils.profiler import Profiler
        with Profiler():
            launch_mode(mode, conf)
    else:
        launch_mode(mode, conf)
Esempio n. 12
0
    async def health(request):
        """Get hive health data. 500 if behind by more than a few secs."""
        #pylint: disable=unused-argument
        is_syncer = Conf.get('sync_to_s3')
        max_head_age = (Conf.get('trail_blocks') + 1) * 3

        try:
            state = await hive_api.db_head_state()
        except OperationalError as e:
            if 'could not connect to server: Connection refused' in str(e):
                logging.error("hive /health could not connect to db")
                state = None
            else:
                raise e

        if not state:
            status = 500
            result = 'db not available'
        elif not is_syncer and state['db_head_age'] > max_head_age:
            status = 500
            result = 'head block age (%s) > max (%s); head block num: %s' % (
                state['db_head_age'], max_head_age, state['db_head_block'])
        else:
            status = 200
            result = 'head block age is %d, head block num is %d' % (
                state['db_head_age'], state['db_head_block'])

        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      sync_service=is_syncer,
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))
Esempio n. 13
0
def run():
    """Run the proper routine as indicated by hive --mode argument."""

    conf = Conf.init_argparse()
    Db.set_shared_instance(conf.db())
    mode = '/'.join(conf.get('mode'))

    if mode == 'server':
        from hive.server.serve import run_server
        run_server(conf=conf)

    elif mode == 'sync':
        from hive.indexer.sync import Sync
        Sync(conf=conf).run()

    elif mode == 'status':
        from hive.db.db_state import DbState
        print(DbState.status())

    else:
        raise Exception("unknown run mode %s" % mode)
Esempio n. 14
0
    async def health(request):
        #pylint: disable=unused-argument
        state = await hive_api.db_head_state()
        max_head_age = (Conf.get('trail_blocks') + 1) * 3

        if state['db_head_age'] > max_head_age:
            status = 500
            result = 'head block age (%s) > max (%s); head block num: %s' % (
                state['db_head_age'], max_head_age, state['db_head_block'])
        else:
            status = 200
            result = 'head block age is %d, head block num is %d' % (
                state['db_head_age'], state['db_head_block'])

        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))
Esempio n. 15
0
def run_server():
    """Configure and launch the API server."""

    log_level = Conf.log_level()
    config.debug = (log_level == logging.DEBUG)
    logging.basicConfig(level=log_level)
    logger = logging.getLogger(__name__)
    logging.getLogger('jsonrpcserver.dispatcher.response').setLevel(log_level)

    methods = build_methods()

    app = web.Application()
    app['config'] = dict()
    app['config']['args'] = Conf.args()
    app['config']['hive.MAX_DB_ROW_RESULTS'] = 100000
    app['config'][
        'hive.DB_QUERY_LIMIT'] = app['config']['hive.MAX_DB_ROW_RESULTS'] + 1
    app['config']['hive.logger'] = logger

    #async def init_db(app):
    #    args = app['config']['args']
    #    db = make_url(args.database_url)
    #    engine = await create_engine(user=db.username,
    #                                 database=db.database,
    #                                 password=db.password,
    #                                 host=db.host,
    #                                 port=db.port,
    #                                 **db.query)
    #    app['db'] = engine
    #
    #async def close_db(app):
    #    app['db'].close()
    #    await app['db'].wait_closed()
    #
    #app.on_startup.append(init_db)
    #app.on_cleanup.append(close_db)
    async def head_age(request):
        """Get hive head block age in seconds. 500 if greater than 15s."""
        #pylint: disable=unused-argument
        healthy_age = 15  # hive is synced if head block within 15s
        curr_age = (await hive_api.db_head_state())['db_head_age']
        status = 500 if curr_age > healthy_age else 200
        return web.Response(status=status, text=str(curr_age))

    async def health(request):
        """Get hive health data. 500 if behind by more than a few secs."""
        #pylint: disable=unused-argument
        is_syncer = Conf.get('sync_to_s3')
        max_head_age = (Conf.get('trail_blocks') + 1) * 3

        try:
            state = await hive_api.db_head_state()
        except OperationalError as e:
            if 'could not connect to server: Connection refused' in str(e):
                logging.error("hive /health could not connect to db")
                state = None
            else:
                raise e

        if not state:
            status = 500
            result = 'db not available'
        elif not is_syncer and state['db_head_age'] > max_head_age:
            status = 500
            result = 'head block age (%s) > max (%s); head block num: %s' % (
                state['db_head_age'], max_head_age, state['db_head_block'])
        else:
            status = 200
            result = 'head block age is %d, head block num is %d' % (
                state['db_head_age'], state['db_head_block'])

        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      sync_service=is_syncer,
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))

    async def jsonrpc_handler(request):
        """Handles all hive jsonrpc API requests."""
        request = await request.text()
        response = await methods.dispatch(request)
        return web.json_response(response,
                                 status=200,
                                 headers={'Access-Control-Allow-Origin': '*'})

    app.router.add_get('/.well-known/healthcheck.json', health)
    app.router.add_get('/head_age', head_age)
    app.router.add_get('/health', health)
    app.router.add_post('/', jsonrpc_handler)

    web.run_app(app, port=app['config']['args'].http_server_port)
Esempio n. 16
0
        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      sync_service=is_syncer,
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))

    async def jsonrpc_handler(request):
        """Handles all hive jsonrpc API requests."""
        request = await request.text()
        response = await methods.dispatch(request)
        return web.json_response(response,
                                 status=200,
                                 headers={'Access-Control-Allow-Origin': '*'})

    app.router.add_get('/.well-known/healthcheck.json', health)
    app.router.add_get('/head_age', head_age)
    app.router.add_get('/health', health)
    app.router.add_post('/', jsonrpc_handler)

    web.run_app(app, port=app['config']['args'].http_server_port)


if __name__ == '__main__':
    Conf.init_argparse()
    run_server()
Esempio n. 17
0
"""Hive server and API tests."""
from hive.conf import Conf
from hive.db.adapter import Db

Db.set_shared_instance(Conf.init_test().db())
Esempio n. 18
0
import datetime
import pytest

from hive.steem.client import SteemClient
from hive.utils.normalize import parse_time
from hive.conf import Conf

Conf.init_argparse(ignore_unknown=True)


def test_instance():
    assert isinstance(SteemClient.instance(), SteemClient)


def test_get_accounts():
    client = SteemClient.instance()
    accounts = client.get_accounts(['steemit', 'test-safari'])
    assert len(accounts) == 2
    assert accounts[0]['name'] == 'steemit'


def test_get_content_batch():
    client = SteemClient.instance()
    tuples = [('test-safari', 'may-spam'), ('test-safari', 'june-spam')]
    posts = client.get_content_batch(tuples)
    assert len(posts) == 2
    assert posts[0]['author'] == 'test-safari'
    assert posts[1]['author'] == 'test-safari'


def test_get_block():
Esempio n. 19
0
 def instance(cls):
     if not cls._instance:
         cls._instance = SteemClient(url=Conf.get('steemd_url'),
                                     max_batch=Conf.get('max_batch'),
                                     max_workers=Conf.get('max_workers'))
     return cls._instance
Esempio n. 20
0
"""Hive server and API tests."""
from hive.conf import Conf
Conf.init_test()
Esempio n. 21
0
def run_server():

    log_level = Conf.log_level()
    config.debug = (log_level == logging.DEBUG)
    logging.basicConfig(level=log_level)
    logger = logging.getLogger(__name__)
    logging.getLogger('jsonrpcserver.dispatcher.response').setLevel(log_level)

    methods = build_methods()

    app = web.Application()
    app['config'] = dict()
    app['config']['args'] = Conf.args()
    app['config']['hive.MAX_DB_ROW_RESULTS'] = 100000
    app['config'][
        'hive.DB_QUERY_LIMIT'] = app['config']['hive.MAX_DB_ROW_RESULTS'] + 1
    app['config']['hive.logger'] = logger

    async def init_db(app):
        args = app['config']['args']
        db = make_url(args.database_url)
        engine = await create_engine(user=db.username,
                                     database=db.database,
                                     password=db.password,
                                     host=db.host,
                                     port=db.port,
                                     **db.query)
        app['db'] = engine

    async def close_db(app):
        app['db'].close()
        await app['db'].wait_closed()

    app.on_startup.append(init_db)
    app.on_cleanup.append(close_db)

    async def health(request):
        #pylint: disable=unused-argument
        state = await hive_api.db_head_state()
        max_head_age = (Conf.get('trail_blocks') + 1) * 3

        if state['db_head_age'] > max_head_age:
            status = 500
            result = 'head block age (%s) > max (%s); head block num: %s' % (
                state['db_head_age'], max_head_age, state['db_head_block'])
        else:
            status = 200
            result = 'head block age is %d, head block num is %d' % (
                state['db_head_age'], state['db_head_block'])

        return web.json_response(
            status=status,
            data=dict(state=state,
                      result=result,
                      status='OK' if status == 200 else 'WARN',
                      source_commit=os.environ.get('SOURCE_COMMIT'),
                      schema_hash=os.environ.get('SCHEMA_HASH'),
                      docker_tag=os.environ.get('DOCKER_TAG'),
                      timestamp=datetime.utcnow().isoformat()))

    async def jsonrpc_handler(request):
        request = await request.text()
        response = await methods.dispatch(request)
        return web.json_response(response,
                                 status=200,
                                 headers={'Access-Control-Allow-Origin': '*'})

    app.router.add_get('/health', health)
    app.router.add_post('/', jsonrpc_handler)

    web.run_app(app, port=app['config']['args'].http_server_port)