From d2d5a5fc48978c92c6e35ef4e9352ff10eb97639 Mon Sep 17 00:00:00 2001 From: Alex Sadleir Date: Mon, 16 Feb 2015 17:46:46 +1100 Subject: [PATCH] Move API analytics thread pool initialisation to plugin configuration One pool should then be available to all controllers avoiding errors with mod_wsgi under Apache as the number of threads grows infinitely. --- ckanext/googleanalytics/__init__.py | 7 +++++ ckanext/googleanalytics/controller.py | 39 ++------------------------- ckanext/googleanalytics/plugin.py | 39 ++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/ckanext/googleanalytics/__init__.py b/ckanext/googleanalytics/__init__.py index 792d600..73c5f7d 100644 --- a/ckanext/googleanalytics/__init__.py +++ b/ckanext/googleanalytics/__init__.py @@ -1 +1,8 @@ +# this is a namespace package +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) # diff --git a/ckanext/googleanalytics/controller.py b/ckanext/googleanalytics/controller.py index d9eb969..e804054 100644 --- a/ckanext/googleanalytics/controller.py +++ b/ckanext/googleanalytics/controller.py @@ -8,8 +8,7 @@ import urllib2 import logging import ckan.logic as logic import hashlib -import Queue -import threading +import plugin from pylons import config from webob.multidict import UnicodeMultiDict @@ -28,42 +27,8 @@ class GAController(BaseController): return render('summary.html') -class AnalyticsPostThread(threading.Thread): - """Threaded Url POST""" - def __init__(self, queue): - threading.Thread.__init__(self) - self.queue = queue - - def run(self): - while True: - # grabs host from queue - data_dict = self.queue.get() - - data = urllib.urlencode(data_dict) - log.debug("Sending API event to Google Analytics: " + data) - # send analytics - urllib2.urlopen( - "http://www.google-analytics.com/collect", - data, - # timeout in seconds - # https://docs.python.org/2/library/urllib2.html#urllib2.urlopen - 10) - - # signals to queue job is done - self.queue.task_done() - - class GAApiController(ApiController): # intercept API calls to record via google analytics - analytics_queue = Queue.Queue() - - def __init__(self): - # spawn a pool of 5 threads, and pass them queue instance - for i in range(5): - t = AnalyticsPostThread(self.analytics_queue) - t.setDaemon(True) - t.start() - def _post_analytics( self, user, request_obj_type, request_function, request_id): if config.get('googleanalytics.id'): @@ -80,7 +45,7 @@ class GAApiController(ApiController): "ea": request_obj_type+request_function, "el": request_id, } - self.analytics_queue.put(data_dict) + plugin.GoogleAnalyticsPlugin.analytics_queue.put(data_dict) def action(self, logic_function, ver=None): try: diff --git a/ckanext/googleanalytics/plugin.py b/ckanext/googleanalytics/plugin.py index bfebc54..7e9655d 100644 --- a/ckanext/googleanalytics/plugin.py +++ b/ckanext/googleanalytics/plugin.py @@ -10,12 +10,40 @@ import ckan.plugins as p import gasnippet from routes.mapper import SubMapper, Mapper as _Mapper -log = logging.getLogger('ckanext.googleanalytics') +import urllib2 +import threading +import Queue + +log = logging.getLogger('ckanext.googleanalytics') class GoogleAnalyticsException(Exception): pass +class AnalyticsPostThread(threading.Thread): + """Threaded Url POST""" + def __init__(self, queue): + threading.Thread.__init__(self) + self.queue = queue + + def run(self): + while True: + # grabs host from queue + data_dict = self.queue.get() + + data = urllib.urlencode(data_dict) + log.debug("Sending API event to Google Analytics: " + data) + # send analytics + urllib2.urlopen( + "http://www.google-analytics.com/collect", + data, + # timeout in seconds + # https://docs.python.org/2/library/urllib2.html#urllib2.urlopen + 10) + + # signals to queue job is done + self.queue.task_done() + class GoogleAnalyticsPlugin(p.SingletonPlugin): p.implements(p.IConfigurable, inherit=True) @@ -24,6 +52,8 @@ class GoogleAnalyticsPlugin(p.SingletonPlugin): p.implements(p.IConfigurer, inherit=True) p.implements(p.ITemplateHelpers) + analytics_queue = Queue.Queue() + def configure(self, config): '''Load config settings for this extension from config file. @@ -56,6 +86,13 @@ class GoogleAnalyticsPlugin(p.SingletonPlugin): if not converters.asbool(config.get('ckan.legacy_templates', 'false')): p.toolkit.add_resource('fanstatic_library', 'ckanext-googleanalytics') + # spawn a pool of 5 threads, and pass them queue instance + for i in range(5): + t = AnalyticsPostThread(self.analytics_queue) + t.setDaemon(True) + t.start() + + def update_config(self, config): '''Change the CKAN (Pylons) environment configuration.