diff --git a/discovery-provider/src/queries/health_check.py b/discovery-provider/src/queries/health_check.py index f24fa27ef4d..66293647dec 100644 --- a/discovery-provider/src/queries/health_check.py +++ b/discovery-provider/src/queries/health_check.py @@ -1,5 +1,6 @@ import logging import os +import redis from flask import Blueprint, jsonify @@ -8,15 +9,17 @@ from src.utils import helpers from src.utils.db_session import get_db from src.utils.config import shared_config +from src.utils.helpers import latest_block_redis_key, latest_block_hash_redis_key logger = logging.getLogger(__name__) - bp = Blueprint("health_check", __name__) web3endpoint = helpers.get_web3_endpoint(shared_config) web3 = Web3(HTTPProvider(web3endpoint)) +redis_url = shared_config["redis"]["url"] +redis = redis.Redis.from_url(url=redis_url) disc_prov_version = helpers.get_discovery_provider_version() @@ -24,19 +27,15 @@ def version(): return jsonify(disc_prov_version), 200 -@bp.route("/health_check", methods=["GET"]) -def health_check(): +def get_db_health_check_results(latest_blocknum, latest_blockhash): db = get_db() with db.scoped_session() as session: - # can extend this in future to include ganache connectivity, how recently a block - # has been added (ex. if it's been more than 30 minutes since last block), etc. - latest_block = web3.eth.getBlock("latest", True) db_block_query = session.query(Block).filter(Block.is_current == True).all() assert len(db_block_query) == 1, "Expected SINGLE row marked as current" health_results = { "web": { - "blocknumber": latest_block.number, - "blockhash": latest_block.hash.hex(), + "blocknumber": latest_blocknum, + "blockhash": latest_blockhash, }, "db": helpers.model_to_dictionary(db_block_query[0]), "healthy": True, @@ -47,8 +46,45 @@ def health_check(): health_results["web"]["blocknumber"] - health_results["db"]["number"] ) health_results["block_difference"] = block_difference + return health_results + +# Consume cached latest block from redis +@bp.route("/health_check", methods=["GET"]) +def health_check(): + # can extend this in future to include ganache connectivity, how recently a block + # has been added (ex. if it's been more than 30 minutes since last block), etc. + latest_block_num = None + latest_block_hash = None + + stored_latest_block_num = redis.get(latest_block_redis_key) + if stored_latest_block_num is not None: + latest_block_num = int(stored_latest_block_num) + + stored_latest_blockhash = redis.get(latest_block_hash_redis_key) + if stored_latest_blockhash is not None: + latest_block_hash = stored_latest_blockhash.decode("utf-8") + + if latest_block_num is None or latest_block_hash is None: + latest_block = web3.eth.getBlock("latest", True) + latest_block_num = latest_block.number + latest_block_hash = latest_block.hash + + health_results = get_db_health_check_results(latest_block_num, latest_block_hash) + + if health_results["block_difference"] > 20: + return jsonify(health_results), 500 + + return jsonify(health_results), 200 + +# Query latest block from web3 provider +@bp.route("/block_check", methods=["GET"]) +def block_check(): + latest_block = web3.eth.getBlock("latest", True) + latest_block_num = latest_block.number + latest_block_hash = latest_block.hash.hex() + health_results = get_db_health_check_results(latest_block_num, latest_block_hash) - if block_difference > 20: - return jsonify(health_results), 500 + if health_results["block_difference"] > 20: + return jsonify(health_results), 500 - return jsonify(health_results), 200 + return jsonify(health_results), 200 diff --git a/discovery-provider/src/tasks/index.py b/discovery-provider/src/tasks/index.py index 1342ba7c4d5..5a2a53a0478 100644 --- a/discovery-provider/src/tasks/index.py +++ b/discovery-provider/src/tasks/index.py @@ -7,7 +7,7 @@ from src.tasks.social_features import social_feature_state_update from src.tasks.playlists import playlist_state_update from src.tasks.user_library import user_library_state_update -from src.utils.helpers import get_ipfs_info_from_cnode_endpoint +from src.utils.helpers import get_ipfs_info_from_cnode_endpoint, latest_block_redis_key, latest_block_hash_redis_key logger = logging.getLogger(__name__) @@ -87,6 +87,12 @@ def get_latest_block(db): latest_block = update_task.web3.eth.getBlock(target_latest_block_number, True) return latest_block +def update_latest_block_redis(): + latest_block_from_chain = update_task.web3.eth.getBlock('latest', True) + redis = update_task.redis + redis.set(latest_block_redis_key, latest_block_from_chain.number) + redis.set(latest_block_hash_redis_key, latest_block_from_chain.hash.hex()) + def index_blocks(self, db, blocks_list): num_blocks = len(blocks_list) block_order_range = range(len(blocks_list) - 1, -1, -1) @@ -458,6 +464,10 @@ def update_task(self): db = update_task.db web3 = update_task.web3 redis = update_task.redis + + # Update redis cache for health check queries + update_latest_block_redis() + # Define lock acquired boolean have_lock = False # Define redis lock object diff --git a/discovery-provider/src/utils/helpers.py b/discovery-provider/src/utils/helpers.py index 2cd9090f05f..0124e24c148 100644 --- a/discovery-provider/src/utils/helpers.py +++ b/discovery-provider/src/utils/helpers.py @@ -173,3 +173,6 @@ def update_ipfs_peers_from_user_endpoint(update_task, cnode_url_list): redis.set(cnode_url, multiaddr, interval) except Exception as e: # pylint: disable=broad-except logger.warning(f"Error connecting to {cnode_url}, {e}") + +latest_block_redis_key = 'latest_block_from_chain' +latest_block_hash_redis_key = 'latest_blockhash_from_chain'