reuse SSL handshake across multiple processes for improved performance
This commit is contained in:
parent
5261f0b80c
commit
dd54f9ff13
3 changed files with 122 additions and 9 deletions
|
@ -29,14 +29,14 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pac
|
||||||
|
|
||||||
from .__about__ import __version__
|
from .__about__ import __version__
|
||||||
from .compat import u, open, is_py3
|
from .compat import u, open, is_py3
|
||||||
from .offlinequeue import Queue
|
|
||||||
from .logger import setup_logging
|
from .logger import setup_logging
|
||||||
from .project import find_project
|
from .offlinequeue import Queue
|
||||||
from .stats import get_file_stats
|
|
||||||
from .packages import argparse
|
from .packages import argparse
|
||||||
from .packages import simplejson as json
|
from .packages import simplejson as json
|
||||||
from .packages import requests
|
|
||||||
from .packages.requests.exceptions import RequestException
|
from .packages.requests.exceptions import RequestException
|
||||||
|
from .project import find_project
|
||||||
|
from .session_cache import SessionCache
|
||||||
|
from .stats import get_file_stats
|
||||||
try:
|
try:
|
||||||
from .packages import tzlocal
|
from .packages import tzlocal
|
||||||
except:
|
except:
|
||||||
|
@ -360,10 +360,13 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
|
||||||
if tz:
|
if tz:
|
||||||
headers['TimeZone'] = u(tz.zone)
|
headers['TimeZone'] = u(tz.zone)
|
||||||
|
|
||||||
|
session_cache = SessionCache()
|
||||||
|
session = session_cache.get()
|
||||||
|
|
||||||
# log time to api
|
# log time to api
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
response = requests.post(api_url, data=request_body, headers=headers,
|
response = session.post(api_url, data=request_body, headers=headers,
|
||||||
proxies=proxies)
|
proxies=proxies)
|
||||||
except RequestException:
|
except RequestException:
|
||||||
exception_data = {
|
exception_data = {
|
||||||
|
@ -385,6 +388,7 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
|
||||||
log.debug({
|
log.debug({
|
||||||
'response_code': response_code,
|
'response_code': response_code,
|
||||||
})
|
})
|
||||||
|
session_cache.save(session)
|
||||||
return True
|
return True
|
||||||
if offline:
|
if offline:
|
||||||
if response_code != 400:
|
if response_code != 400:
|
||||||
|
@ -410,6 +414,7 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
|
||||||
'response_code': response_code,
|
'response_code': response_code,
|
||||||
'response_content': response_content,
|
'response_content': response_content,
|
||||||
})
|
})
|
||||||
|
session_cache.delete()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
wakatime.queue
|
wakatime.offlinequeue
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Queue for offline time logging.
|
Queue for saving heartbeats while offline.
|
||||||
http://wakatime.com
|
|
||||||
|
|
||||||
:copyright: (c) 2014 Alan Hamlett.
|
:copyright: (c) 2014 Alan Hamlett.
|
||||||
:license: BSD, see LICENSE for more details.
|
:license: BSD, see LICENSE for more details.
|
||||||
|
|
109
wakatime/session_cache.py
Normal file
109
wakatime/session_cache.py
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
wakatime.session_cache
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Persist requests.Session for multiprocess SSL handshake pooling.
|
||||||
|
|
||||||
|
:copyright: (c) 2015 Alan Hamlett.
|
||||||
|
:license: BSD, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sqlite3
|
||||||
|
HAS_SQL = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_SQL = False
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'packages'))
|
||||||
|
|
||||||
|
from .packages import requests
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger('WakaTime')
|
||||||
|
|
||||||
|
|
||||||
|
class SessionCache(object):
|
||||||
|
DB_FILE = os.path.join(os.path.expanduser('~'), '.wakatime.db')
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
conn = sqlite3.connect(self.DB_FILE)
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS session (
|
||||||
|
value BLOB)
|
||||||
|
''')
|
||||||
|
return (conn, c)
|
||||||
|
|
||||||
|
|
||||||
|
def save(self, session):
|
||||||
|
"""Saves a requests.Session object for the next heartbeat process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not HAS_SQL:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
conn, c = self.connect()
|
||||||
|
c.execute('DELETE FROM session')
|
||||||
|
values = {
|
||||||
|
'value': pickle.dumps(session),
|
||||||
|
}
|
||||||
|
c.execute('INSERT INTO session VALUES (:value)', values)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
except:
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
"""Returns a requests.Session object.
|
||||||
|
|
||||||
|
Gets Session from sqlite3 cache or creates a new Session.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not HAS_SQL:
|
||||||
|
return requests.session()
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn, c = self.connect()
|
||||||
|
except:
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
return requests.session()
|
||||||
|
|
||||||
|
session = None
|
||||||
|
try:
|
||||||
|
c.execute('BEGIN IMMEDIATE')
|
||||||
|
c.execute('SELECT value FROM session LIMIT 1')
|
||||||
|
row = c.fetchone()
|
||||||
|
if row is not None:
|
||||||
|
session = pickle.loads(row[0])
|
||||||
|
except:
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn.close()
|
||||||
|
except:
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
|
||||||
|
return session if session is not None else requests.session()
|
||||||
|
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""Clears all cached Session objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not HAS_SQL:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
conn, c = self.connect()
|
||||||
|
c.execute('DELETE FROM session')
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
except:
|
||||||
|
log.error(traceback.format_exc())
|
Loading…
Reference in a new issue