diff --git a/EXAMPLE_hivemind_upstream_config.json b/EXAMPLE_hivemind_upstream_config.json new file mode 100644 index 0000000000000000000000000000000000000000..fa82760175bce127d27c6d2d14a4dfdcd639c4d3 --- /dev/null +++ b/EXAMPLE_hivemind_upstream_config.json @@ -0,0 +1,285 @@ +{ + "limits": { + "accounts_blacklist": [ + "accounttoblock" + ] + }, + "upstreams": [ + { + "name": "steemd", + "translate_to_appbase": true, + "urls": [ + [ + "steemd", + "https://your.steemd.url" + ] + ], + "ttls": [ + [ + "steemd", + 3 + ] + ], + "timeouts": [ + [ + "steemd", + 3 + ] + ] + }, + { + "name": "appbase", + "urls": [ + [ + "appbase", + "https://your.steemd.url" + ], + [ + "appbase.account_history_api", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_account_history", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_ops_in_block", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_followers", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_following", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_follow_count", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_trending", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_hot", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_promoted", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_created", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_blog", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_feed", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_comments", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_replies_by_last_update", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_trending_tags", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_discussions_by_author_before_date", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_post_discussions_by_payout", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_comment_discussions_by_payout", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_blog", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_blog_entries", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_account_votes", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_state", + "https://your.hivemind.url" + ], + [ + "appbase.condenser_api.get_state.params=['witnesses']", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_state.params=['/witnesses']", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_state.params=['/~witnesses']", + "https://your.account.history.steemd.url" + ], + [ + "appbase.condenser_api.get_state.params=['~witnesses']", + "https://your.account.history.steemd.url" + ], + [ + "appbase.follow_api", + "https://your.hivemind.url" + ], + [ + "appbase.tags_api", + "https://your.hivemind.url" + ] + ], + "ttls": [ + [ + "appbase", + 3 + ], + [ + "appbase.login_api", + -1 + ], + [ + "appbase.network_broadcast_api", + -1 + ], + [ + "appbase.follow_api", + 10 + ], + [ + "appbase.market_history_api", + 1 + ], + [ + "appbase.condenser_api", + 3 + ], + [ + "appbase.condenser_api.get_block", + -2 + ], + [ + "appbase.condenser_api.get_block_header", + -2 + ], + [ + "appbase.condenser_api.get_content", + 1 + ], + [ + "appbase.condenser_api.get_state", + 1 + ], + [ + "appbase.condenser_api.get_state.params=['/trending']", + 30 + ], + [ + "appbase.condenser_api.get_state.params=['trending']", + 30 + ], + [ + "appbase.condenser_api.get_state.params=['/hot']", + 30 + ], + [ + "appbase.condenser_api.get_state.params=['/welcome']", + 30 + ], + [ + "appbase.condenser_api.get_state.params=['/promoted']", + 30 + ], + [ + "appbase.condenser_api.get_state.params=['/created']", + 10 + ], + [ + "appbase.condenser_api.get_dynamic_global_properties", + 1 + ] + ], + "timeouts": [ + [ + "appbase", + 3 + ], + [ + "appbase.network_broadcast_api", + 0 + ], + [ + "appbase.chain_api.push_block", + 0 + ], + [ + "appbase.chain_api.push_transaction", + 0 + ], + [ + "appbase.condenser_api.broadcast_block", + 0 + ], + [ + "appbase.condenser_api.broadcast_transaction", + 0 + ], + [ + "appbase.condenser_api.broadcast_transaction_synchronous", + 0 + ], + [ + "appbase.condenser_api.get_account_votes", + 20 + ], + [ + "appbase.condenser_api.get_ops_in_block.params=[2889020,false]", + 20 + ], + [ + "appbase.account_history_api.get_ops_in_block.params={\"block_num\":2889020,\"only_virtual\":false}", + 20 + ] + ] + }, + { + "name": "hive", + "urls": [ + [ + "hive", + "https://your.hivemind.url" + ] + ], + "ttls": [ + [ + "hive", + -1 + ] + ], + "timeouts": [ + [ + "hive", + 30 + ] + ] + } + ] + } diff --git a/README.md b/README.md index 77c6f88ad811b6a0909f7f9ce01dacd786ffc681..8296f767f5abbfacaaedcc7acebc222dbf6cff3d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The easiest way to get up and running with jussi is by running it in a docker co 1) Copy the example `DEV_config.json` to a local directory and make any necessary edits. 2) Run this docker command (replace `/path/to/config.json` with the path to your config file): ``` -docker run -it --env JUSSI_UPSTREAM_CONFIG_FILE=/app/config.json -v /path/to/config.json:/app/config.json -p 9000:9000 steemit/jussi:latest +docker run -it --env JUSSI_UPSTREAM_CONFIG_FILE=/app/config.json -v /path/to/config.json:/app/config.json -p 8080:8080 steemit/jussi:latest ``` You can build jussi using docker which will run it's full test suite with `docker build -t="myname/jussi:latest" .` @@ -147,4 +147,4 @@ Certain features of jussi can be configured using environment variables. If you ## Additional documentation -For more indepth documentation on jussi including examples, check out the section on it in the steem dev portal: https://developers.steem.io/services/#services-jussi \ No newline at end of file +For more indepth documentation on jussi including examples, check out the section on it in the steem dev portal: https://developers.steem.io/services/#services-jussi diff --git a/jussi/cache/cache_group.py b/jussi/cache/cache_group.py index afe97e7e1630c8bb8a365a48da1a27a63963aa91..83290b47b5a5b807f60912bb30ea28dfefc1870f 100644 --- a/jussi/cache/cache_group.py +++ b/jussi/cache/cache_group.py @@ -33,7 +33,7 @@ from .utils import merge_cached_responses logger = structlog.getLogger(__name__) -BATCH_IRREVERSIBLE_TTL_SET = frozenset([TTL.NO_EXPIRE_IF_IRREVERSIBLE]) +BATCH_IRREVERSIBLE_TTL_SET = frozenset([TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE]) # types CacheTTLValue = TypeVar('CacheTTL', int, float, type(None)) @@ -188,7 +188,7 @@ class CacheGroup: ) -> None: key = jsonrpc_cache_key(request) ttl = ttl or request.upstream.ttl - if ttl == TTL.NO_EXPIRE_IF_IRREVERSIBLE: + if ttl == TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE: last_irreversible_block_num = last_irreversible_block_num or \ self._memory_cache.gets('last_irreversible_block_num') or \ await self.get('last_irreversible_block_num') @@ -218,7 +218,7 @@ class CacheGroup: else: new_ttls = [] for i, ttl in enumerate(ttls): - if ttl == TTL.NO_EXPIRE_IF_IRREVERSIBLE: + if ttl == TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE: ttl = irreversible_ttl(responses[i], last_irreversible_block_num) new_ttls.append(ttl) triplets = filter(lambda p: p[0] != TTL.NO_CACHE, zip(ttls, requests, responses)) diff --git a/jussi/cache/ttl.py b/jussi/cache/ttl.py index e433a986ec19a515126d695c4cbd88ee577dfa7c..b78a1af34fbd5cfc5e0816a8883b191cc404a479 100644 --- a/jussi/cache/ttl.py +++ b/jussi/cache/ttl.py @@ -8,11 +8,11 @@ Method Settings - TTL is an integer value in seconds. Integers <= 0 have special meaning - A TTL of `0` won't expire - A TTL of `-1` wont be cached - - A TTL of `-2` will be cached without expiration only if it is 'irreversible' in terms of blockchain consesus + - A TTL of `-2` will be cached with default expiration only if it is 'irreversible' in terms of blockchain consesus - For readabilty/writabilty, there are shorthand variables for these 'special' TTL values: - `NO_EXPIRE` == 0 - `NO_CACHE` == -1 - - `NO_EXPIRE_IF_IRREVERSIBLE` == -2 + - `DEFAULT_EXPIRE_IF_IRREVERSIBLE` == -2 """ @@ -23,7 +23,7 @@ class TTL(Enum): DEFAULT_TTL = 3 NO_EXPIRE = None NO_CACHE = -1 - NO_EXPIRE_IF_IRREVERSIBLE = -2 + DEFAULT_EXPIRE_IF_IRREVERSIBLE = -2 # pylint: disable=no-else-return def __eq__(self, other: int) -> bool: diff --git a/jussi/cache/utils.py b/jussi/cache/utils.py index 6735a2d71d2912ca3dd1a7995d5ac4b91e8f461c..6a3bfe2aae356cccaed6947b6f501ed0aaf7c664 100644 --- a/jussi/cache/utils.py +++ b/jussi/cache/utils.py @@ -30,8 +30,6 @@ def irreversible_ttl(jsonrpc_response: dict=None, return TTL.NO_CACHE try: jrpc_block_num = block_num_from_jsonrpc_response(jsonrpc_response) - if jrpc_block_num and jrpc_block_num <= last_irreversible_block_num: - return TTL.NO_EXPIRE return TTL.DEFAULT_TTL except Exception as e: logger.warning( diff --git a/jussi/upstream.py b/jussi/upstream.py index 1ad52ff717222f0f1fd703ba29b34ff89f79c828..e25ff584e84ec03aee2a5a01dcad6806c4aa297d 100644 --- a/jussi/upstream.py +++ b/jussi/upstream.py @@ -18,7 +18,7 @@ from .errors import InvalidUpstreamURL logger = structlog.get_logger(__name__) -ACCOUNT_TRANSFER_PATTERN = re.compile(r'^\/?(@([^\/\s]+)/transfers|~?witnesses)$') +ACCOUNT_TRANSFER_PATTERN = re.compile(r'^\/?(@([^\/\s]+)/transfers|~?witnesses|proposals)$') # ------------------- diff --git a/tests/test_ttls.py b/tests/test_ttls.py index aa94e503a7a4c61c0be73a10821595cbd16495d0..7ca257a02f076329658537582fa58743640087bd 100644 --- a/tests/test_ttls.py +++ b/tests/test_ttls.py @@ -35,8 +35,8 @@ non_ttl_rpc_req = jsonrpc_from_request(dummy_request, 0, {"id": "1", "jsonrpc": (ttl_rpc_req, rpc_resp, 999, TTL.DEFAULT_TTL), # cache when last_block_num >= response block_num - (ttl_rpc_req, rpc_resp, 1000, TTL.NO_EXPIRE), - (ttl_rpc_req, rpc_resp, 1001, TTL.NO_EXPIRE), + (ttl_rpc_req, rpc_resp, 1000, TTL.DEFAULT_TTL), + (ttl_rpc_req, rpc_resp, 1001, TTL.DEFAULT_TTL), # don't cache when bad/missing response block_num (ttl_rpc_req, {}, 2000, TTL.NO_CACHE), @@ -54,7 +54,7 @@ def test_ttls(rpc_req, rpc_resp, last_block_num, expected): (TTL.NO_CACHE, -1), (TTL.DEFAULT_TTL, 3), (TTL.NO_EXPIRE, None), - (TTL.NO_EXPIRE_IF_IRREVERSIBLE, -2), + (TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE, -2), ] ) def test_ttl_eq(ttl, eq): @@ -65,7 +65,7 @@ def test_ttl_eq(ttl, eq): @pytest.mark.parametrize('ttl', [ (TTL.NO_CACHE), (TTL.DEFAULT_TTL), - (TTL.NO_EXPIRE_IF_IRREVERSIBLE) + (TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE) ] ) def test_ttl_gt(ttl): @@ -75,7 +75,7 @@ def test_ttl_gt(ttl): @pytest.mark.parametrize('ttl', [ (TTL.NO_CACHE), (TTL.DEFAULT_TTL), - (TTL.NO_EXPIRE_IF_IRREVERSIBLE) + (TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE) ] ) def test_ttl_ge(ttl): @@ -85,7 +85,7 @@ def test_ttl_ge(ttl): @pytest.mark.parametrize('ttl', [ (TTL.NO_CACHE), (TTL.DEFAULT_TTL), - (TTL.NO_EXPIRE_IF_IRREVERSIBLE) + (TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE) ] ) def test_ttl_lt(ttl): @@ -95,7 +95,7 @@ def test_ttl_lt(ttl): @pytest.mark.parametrize('ttl', [ (TTL.NO_CACHE), (TTL.DEFAULT_TTL), - (TTL.NO_EXPIRE_IF_IRREVERSIBLE) + (TTL.DEFAULT_EXPIRE_IF_IRREVERSIBLE) ] ) def test_ttl_le(ttl):