Skip to content

Commit 8ac1384

Browse files
committed
Added one more layer of memcache to avoid recalculation of user data on data representation style changes.
1 parent 21bbc91 commit 8ac1384

1 file changed

Lines changed: 77 additions & 64 deletions

File tree

app/core.py

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,72 @@ def reduce_commits_by_repo(aggr, commit):
6767
def get_option(self, name, defval):
6868
return False if self.request.get(name, defval) == '0' else True
6969

70+
def calculate_user_values(self, username):
71+
try:
72+
github_user = User.get(username)
73+
except pyresto.Error:
74+
self.response.set_status(404) # not 100% sure but good enough
75+
self.render('errors/404')
76+
return
77+
except Exception as err:
78+
self.response.set_status(500)
79+
logging.error(err)
80+
return
81+
82+
languages = User.sort_languages(github_user.language_stats)
83+
fork_count = sum((1 for repo in github_user.repos if repo.fork))
84+
85+
today = datetime.datetime.today()
86+
recent_than = today - datetime.timedelta(days=RECENT_DAYS)
87+
own_commits = github_user.get_latest_commits(recent_than)
88+
89+
commits_by_repo = reduce(self.reduce_commits_by_repo,
90+
own_commits, dict())
91+
if commits_by_repo:
92+
last_project = max(commits_by_repo, key=commits_by_repo.get)
93+
else:
94+
last_project = ''
95+
logging.info(commits_by_repo)
96+
if last_project:
97+
last_project_url = [repo.html_url for repo in github_user.repos
98+
if repo.name == last_project][0]
99+
else:
100+
last_project_url = None
101+
102+
commits_by_date = reduce(self.reduce_commits_by_date,
103+
own_commits, dict())
104+
range = daterange(recent_than, today)
105+
for d in range:
106+
key = unicode(d.date())
107+
if key not in commits_by_date:
108+
commits_by_date[key] = 0
109+
110+
commit_data = [commits_by_date[d] for d in sorted(commits_by_date)]
111+
max_commits = max(commit_data)
112+
logging.debug('Commit data %s', str(commit_data))
113+
commit_sparkline = 'data:image/png;base64,' +\
114+
base64.b64encode(
115+
sparklines.impulse(commit_data,
116+
below_color='SlateGray',
117+
width=3,
118+
dmin=0,
119+
dmax=max(commit_data)
120+
),
121+
)
122+
123+
return {'user': github_user.__dict__,
124+
'own_repos': github_user.public_repos - fork_count,
125+
'fork_repos': fork_count,
126+
'languages': languages,
127+
'project_followers': github_user.project_followers -\
128+
github_user.public_repos,
129+
'commit_sparkline': commit_sparkline,
130+
'max_commits': max_commits,
131+
'last_project': last_project,
132+
'last_project_url': last_project_url,
133+
'days': RECENT_DAYS
134+
}
135+
70136
def get(self, username):
71137
support = self.get_option('s', '0')
72138
analytics = self.get_option('a', '1')
@@ -78,72 +144,18 @@ def get(self, username):
78144
if cached_data:
79145
return self.write(cached_data)
80146
else:
81-
try:
82-
github_user = User.get(username)
83-
except pyresto.Error:
84-
self.response.set_status(404) # not 100% sure but good enough
85-
self.render('errors/404')
86-
return
87-
except Exception as err:
88-
self.response.set_status(500)
89-
logging.error(err)
90-
return
147+
memcache_data_key = '!data!{}'.format(username)
148+
values = json.loads(memcache.get(memcache_data_key) or '{}')
149+
if not values:
150+
# Caution, the method below may alter state.
151+
values = self.calculate_user_values(username)
91152

92-
languages = User.sort_languages(github_user.language_stats)
93-
fork_count = sum((1 for repo in github_user.repos if repo.fork))
94-
95-
today = datetime.datetime.today()
96-
recent_than = today - datetime.timedelta(days=RECENT_DAYS)
97-
own_commits = github_user.get_latest_commits(recent_than)
153+
if not values: # still don't have the values, something went wrong
154+
return
98155

99-
commits_by_repo = reduce(self.reduce_commits_by_repo,
100-
own_commits, dict())
101-
if commits_by_repo:
102-
last_project = max(commits_by_repo, key=commits_by_repo.get)
103-
else:
104-
last_project = ''
105-
logging.info(commits_by_repo)
106-
if last_project:
107-
last_project_url = [repo.html_url for repo in github_user.repos
108-
if repo.name == last_project][0]
109-
else:
110-
last_project_url = None
111-
112-
commits_by_date = reduce(self.reduce_commits_by_date,
113-
own_commits, dict())
114-
range = daterange(recent_than, today)
115-
for d in range:
116-
key = unicode(d.date())
117-
if key not in commits_by_date:
118-
commits_by_date[key] = 0
119-
120-
commit_data = [commits_by_date[d] for d in sorted(commits_by_date)]
121-
max_commits = max(commit_data)
122-
logging.debug('Commit data %s', str(commit_data))
123-
commit_sparkline = 'data:image/png;base64,' + \
124-
base64.b64encode(
125-
sparklines.impulse(commit_data,
126-
below_color='SlateGray',
127-
width=3,
128-
dmin=0,
129-
dmax=max(commit_data)
130-
),
131-
)
132-
133-
values = {'user': github_user.__dict__,
134-
'own_repos': github_user.public_repos - fork_count,
135-
'fork_repos': fork_count,
136-
'languages': languages,
137-
'project_followers': github_user.project_followers - \
138-
github_user.public_repos,
139-
'commit_sparkline': commit_sparkline,
140-
'max_commits': max_commits,
141-
'last_project': last_project,
142-
'last_project_url': last_project_url,
143-
'support': support,
144-
'analytics': analytics,
145-
'days': RECENT_DAYS
146-
}
156+
if not memcache.set(memcache_data_key,
157+
json.dumps(values), MEMCACHE_EXPIRATION):
158+
logging.error('Memcache set failed for user data %s', username)
147159

148160
if jsonp:
149161
values = {'jsonp': jsonp, 'data': json.dumps(values)}
@@ -152,6 +164,7 @@ def get(self, username):
152164
charset='utf-8')
153165
output = self.render('jsonp', values, '.js', False)
154166
else:
167+
values.update({'support': support, 'analytics': analytics})
155168
output = self.render('badge', values)
156169

157170
if not memcache.set(memcache_key, output, MEMCACHE_EXPIRATION):

0 commit comments

Comments
 (0)