Tune performance
- Added threading to gunicorn instance - Changed cache to cachetools's TTL cache since it uses LRU if the cache is full - Increased cache sizes 1.5x
This commit is contained in:
parent
5fccffc2f0
commit
e303af090d
|
@ -100,3 +100,5 @@ $RECYCLE.BIN/
|
||||||
|
|
||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
|
*.gcloudignore
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
runtime: python38
|
runtime: python38
|
||||||
|
|
||||||
entrypoint: gunicorn -b :$PORT twitchrss:app
|
entrypoint: gunicorn -b :$PORT -k gthread --threads 2 twitchrss:app
|
||||||
|
|
||||||
env_variables:
|
env_variables:
|
||||||
TWITCH_CLIENT_ID: __INSERT_TWITCH_CLIENT_ID_HERE__
|
TWITCH_CLIENT_ID: __INSERT_TWITCH_CLIENT_ID_HERE__
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
appdirs==1.4.3
|
appdirs==1.4.3
|
||||||
CacheControl==0.12.6
|
CacheControl==0.12.6
|
||||||
|
cachetools==4.1.1
|
||||||
certifi==2019.11.28
|
certifi==2019.11.28
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
click==7.1.2
|
click==7.1.2
|
||||||
|
@ -7,7 +8,6 @@ colorama==0.4.3
|
||||||
contextlib2==0.6.0
|
contextlib2==0.6.0
|
||||||
distlib==0.3.0
|
distlib==0.3.0
|
||||||
distro==1.4.0
|
distro==1.4.0
|
||||||
expiringdict==1.2.1
|
|
||||||
Flask==1.1.2
|
Flask==1.1.2
|
||||||
gunicorn==20.0.4
|
gunicorn==20.0.4
|
||||||
html5lib==1.0.1
|
html5lib==1.0.1
|
||||||
|
|
|
@ -22,14 +22,14 @@ import logging
|
||||||
import re
|
import re
|
||||||
from os import environ
|
from os import environ
|
||||||
from feedformatter import Feed
|
from feedformatter import Feed
|
||||||
from expiringdict import ExpiringDict
|
from cachetools import cached, TTLCache, LRUCache
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import gzip
|
import gzip
|
||||||
|
|
||||||
|
|
||||||
VOD_URL_TEMPLATE = 'https://api.twitch.tv/kraken/channels/%s/videos?broadcast_type=archive,highlight,upload&limit=10'
|
VOD_URL_TEMPLATE = 'https://api.twitch.tv/kraken/channels/%s/videos?broadcast_type=archive,highlight,upload&limit=10'
|
||||||
USERID_URL_TEMPLATE = 'https://api.twitch.tv/kraken/users?login=%s'
|
USERID_URL_TEMPLATE = 'https://api.twitch.tv/kraken/users?login=%s'
|
||||||
VODCACHE_LIFETIME = 600
|
VODCACHE_LIFETIME = 10 * 60
|
||||||
USERIDCACHE_LIFETIME = 24 * 60 * 60
|
USERIDCACHE_LIFETIME = 24 * 60 * 60
|
||||||
CHANNEL_FILTER = re.compile("^[a-zA-Z0-9_]{2,25}$")
|
CHANNEL_FILTER = re.compile("^[a-zA-Z0-9_]{2,25}$")
|
||||||
TWITCH_CLIENT_ID = environ.get("TWITCH_CLIENT_ID")
|
TWITCH_CLIENT_ID = environ.get("TWITCH_CLIENT_ID")
|
||||||
|
@ -41,9 +41,6 @@ if not TWITCH_CLIENT_ID:
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
vodcache = ExpiringDict(max_len=200, max_age_seconds=VODCACHE_LIFETIME)
|
|
||||||
useridcache = ExpiringDict(max_len=1000, max_age_seconds=USERIDCACHE_LIFETIME)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/vod/<string:channel>', methods=['GET', 'HEAD'])
|
@app.route('/vod/<string:channel>', methods=['GET', 'HEAD'])
|
||||||
def vod(channel):
|
def vod(channel):
|
||||||
|
@ -63,31 +60,29 @@ def vodonly(channel):
|
||||||
|
|
||||||
def get_inner(channel, add_live=True):
|
def get_inner(channel, add_live=True):
|
||||||
userid_json = fetch_userid(channel)
|
userid_json = fetch_userid(channel)
|
||||||
|
if not userid_json:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
(channel_display_name, channel_id) = extract_userid(json.loads(userid_json))
|
(channel_display_name, channel_id) = extract_userid(json.loads(userid_json))
|
||||||
|
|
||||||
channel_json = fetch_vods(channel_id)
|
channel_json = fetch_vods(channel_id)
|
||||||
|
if not channel_json:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
decoded_json = json.loads(channel_json)
|
decoded_json = json.loads(channel_json)
|
||||||
rss_data = construct_rss(channel, decoded_json, channel_display_name, add_live)
|
rss_data = construct_rss(channel, decoded_json, channel_display_name, add_live)
|
||||||
headers = {'Content-Type': 'application/rss+xml'}
|
headers = {'Content-Type': 'application/rss+xml'}
|
||||||
return rss_data, headers
|
return rss_data, headers
|
||||||
|
|
||||||
|
|
||||||
|
@cached(cache=TTLCache(maxsize=2000, ttl=USERIDCACHE_LIFETIME))
|
||||||
def fetch_userid(channel_name):
|
def fetch_userid(channel_name):
|
||||||
return fetch_or_cache_object(channel_name, useridcache, USERID_URL_TEMPLATE)
|
return fetch_json(channel_name, USERID_URL_TEMPLATE)
|
||||||
|
|
||||||
|
|
||||||
|
@cached(cache=TTLCache(maxsize=400, ttl=VODCACHE_LIFETIME))
|
||||||
def fetch_vods(channel_id):
|
def fetch_vods(channel_id):
|
||||||
return fetch_or_cache_object(channel_id, vodcache, VOD_URL_TEMPLATE)
|
return fetch_json(channel_id, VOD_URL_TEMPLATE)
|
||||||
|
|
||||||
|
|
||||||
def fetch_or_cache_object(key, cachedict, url_template):
|
|
||||||
json_data = cachedict.get(key)
|
|
||||||
if not json_data:
|
|
||||||
json_data = fetch_json(key, url_template)
|
|
||||||
if not json_data:
|
|
||||||
abort(404)
|
|
||||||
else:
|
|
||||||
cachedict[key] = json_data
|
|
||||||
return json_data
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_json(id, url_template):
|
def fetch_json(id, url_template):
|
||||||
|
@ -112,7 +107,7 @@ def fetch_json(id, url_template):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning("Fetch exception caught: %s" % e)
|
logging.warning("Fetch exception caught: %s" % e)
|
||||||
retries += 1
|
retries += 1
|
||||||
return None
|
abort(503)
|
||||||
|
|
||||||
|
|
||||||
def extract_userid(user_info):
|
def extract_userid(user_info):
|
||||||
|
|
Loading…
Reference in New Issue