Commit ec787a99 by adeel khan Committed by GitHub

Merge pull request #15332 from…

Merge pull request #15332 from edx/adeel/LEARNER-1188_Setting_connection_timeout_value_for_sailthru_api_call

Implementing connection timeout for sailthru api call.
parents 95b3055f 52e28d91
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('email_marketing', '0004_emailmarketingconfiguration_welcome_email_send_delay'),
]
operations = [
migrations.AddField(
model_name='emailmarketingconfiguration',
name='user_registration_cookie_timeout_delay',
field=models.FloatField(default=1.5, help_text='The number of seconds to delay/timeout wait to get cookie values from sailthru.'),
),
]
...@@ -136,6 +136,14 @@ class EmailMarketingConfiguration(ConfigurationModel): ...@@ -136,6 +136,14 @@ class EmailMarketingConfiguration(ConfigurationModel):
) )
) )
# The number of seconds to delay/timeout wait to get cookie values from sailthru.
user_registration_cookie_timeout_delay = models.fields.FloatField(
default=1.5,
help_text=_(
"The number of seconds to delay/timeout wait to get cookie values from sailthru."
)
)
def __unicode__(self): def __unicode__(self):
return u"Email marketing configuration: New user list %s, Activation template: %s" % \ return u"Email marketing configuration: New user list %s, Activation template: %s" % \
(self.sailthru_new_user_list, self.sailthru_activation_template) (self.sailthru_new_user_list, self.sailthru_activation_template)
...@@ -9,9 +9,10 @@ from django.conf import settings ...@@ -9,9 +9,10 @@ from django.conf import settings
from django.dispatch import receiver from django.dispatch import receiver
from sailthru.sailthru_client import SailthruClient from sailthru.sailthru_client import SailthruClient
from sailthru.sailthru_error import SailthruClientError from sailthru.sailthru_error import SailthruClientError
from celery.exceptions import TimeoutError
from email_marketing.models import EmailMarketingConfiguration from email_marketing.models import EmailMarketingConfiguration
from lms.djangoapps.email_marketing.tasks import update_user, update_user_email from lms.djangoapps.email_marketing.tasks import update_user, update_user_email, get_email_cookies_via_sailthru
from student.cookies import CREATE_LOGON_COOKIE from student.cookies import CREATE_LOGON_COOKIE
from student.views import REGISTER_USER from student.views import REGISTER_USER
from util.model_utils import USER_FIELD_CHANGED from util.model_utils import USER_FIELD_CHANGED
...@@ -54,41 +55,34 @@ def add_email_marketing_cookies(sender, response=None, user=None, ...@@ -54,41 +55,34 @@ def add_email_marketing_cookies(sender, response=None, user=None,
if sailthru_content: if sailthru_content:
post_parms['cookies'] = {'anonymous_interest': sailthru_content} post_parms['cookies'] = {'anonymous_interest': sailthru_content}
try: time_before_call = datetime.datetime.now()
sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret) sailthru_response = get_email_cookies_via_sailthru.delay(user.email, post_parms)
log.info(
'Sending to Sailthru the user interest cookie [%s] for user [%s]',
post_parms.get('cookies', ''),
user.email
)
time_before_call = datetime.datetime.now()
sailthru_response = \ try:
sailthru_client.api_post("user", post_parms) # synchronous call to get result of an asynchronous celery task, with timeout
sailthru_response.get(timeout=email_config.user_registration_cookie_timeout_delay,
propagate=True)
cookie = sailthru_response.result
except TimeoutError as exc:
log.error("Timeout error while attempting to obtain cookie from Sailthru: %s", unicode(exc))
return response
except SailthruClientError as exc: except SailthruClientError as exc:
log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc)) log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc))
return response return response
if sailthru_response.is_ok(): if not cookie:
if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']: log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email)
cookie = sailthru_response.json['keys']['cookie'] return response
response.set_cookie(
'sailthru_hid',
cookie,
max_age=365 * 24 * 60 * 60, # set for 1 year
domain=settings.SESSION_COOKIE_DOMAIN,
path='/',
)
_log_sailthru_api_call_time(time_before_call)
else:
log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email)
else: else:
error = sailthru_response.get_error() response.set_cookie(
# generally invalid email address 'sailthru_hid',
log.info("Error attempting to obtain cookie from Sailthru: %s", error.get_message()) cookie,
max_age=365 * 24 * 60 * 60, # set for 1 year
domain=settings.SESSION_COOKIE_DOMAIN,
path='/',
)
_log_sailthru_api_call_time(time_before_call)
return response return response
......
...@@ -17,6 +17,46 @@ log = logging.getLogger(__name__) ...@@ -17,6 +17,46 @@ log = logging.getLogger(__name__)
SAILTHRU_LIST_CACHE_KEY = "email.marketing.cache" SAILTHRU_LIST_CACHE_KEY = "email.marketing.cache"
@task(bind=True)
def get_email_cookies_via_sailthru(self, user_email, post_parms):
"""
Adds/updates Sailthru cookie information for a new user.
Args:
post_parms(dict): User profile information to pass as 'vars' to Sailthru
Returns:
cookie(str): cookie fetched from Sailthru
"""
email_config = EmailMarketingConfiguration.current()
if not email_config.enabled:
return None
try:
sailthru_client = SailthruClient(email_config.sailthru_key, email_config.sailthru_secret)
log.info(
'Sending to Sailthru the user interest cookie [%s] for user [%s]',
post_parms.get('cookies', ''),
user_email
)
sailthru_response = sailthru_client.api_post("user", post_parms)
except SailthruClientError as exc:
log.error("Exception attempting to obtain cookie from Sailthru: %s", unicode(exc))
raise SailthruClientError
if sailthru_response.is_ok():
if 'keys' in sailthru_response.json and 'cookie' in sailthru_response.json['keys']:
cookie = sailthru_response.json['keys']['cookie']
return cookie
else:
log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user_email)
else:
error = sailthru_response.get_error()
# generally invalid email address
log.info("Error attempting to obtain cookie from Sailthru: %s", error.get_message())
return None
# pylint: disable=not-callable # pylint: disable=not-callable
@task(bind=True, default_retry_delay=3600, max_retries=24) @task(bind=True, default_retry_delay=3600, max_retries=24)
def update_user(self, sailthru_vars, email, site=None, new_user=False, activation=False): def update_user(self, sailthru_vars, email, site=None, new_user=False, activation=False):
......
...@@ -25,7 +25,8 @@ from email_marketing.tasks import ( ...@@ -25,7 +25,8 @@ from email_marketing.tasks import (
_get_list_from_email_marketing_provider, _get_list_from_email_marketing_provider,
_get_or_create_user_list, _get_or_create_user_list,
update_user, update_user,
update_user_email update_user_email,
get_email_cookies_via_sailthru
) )
from student.tests.factories import UserFactory, UserProfileFactory from student.tests.factories import UserFactory, UserProfileFactory
from util.json_request import JsonResponse from util.json_request import JsonResponse
...@@ -98,13 +99,10 @@ class EmailMarketingTests(TestCase): ...@@ -98,13 +99,10 @@ class EmailMarketingTests(TestCase):
self.request.COOKIES['anonymous_interest'] = 'cookie_content' self.request.COOKIES['anonymous_interest'] = 'cookie_content'
mock_get_current_request.return_value = self.request mock_get_current_request.return_value = self.request
mock_sailthru.return_value = SailthruResponse(JsonResponse({'keys': {'cookie': 'test_cookie'}})) mock_sailthru.return_value = SailthruResponse(JsonResponse({'keys': {'cookie': 'test_cookie'}}))
cookie_log = "Sending to Sailthru the user interest cookie [{'anonymous_interest': 'cookie_content'}]" \
' for user [test@edx.org]'
with LogCapture(LOGGER_NAME, level=logging.INFO) as logger: with LogCapture(LOGGER_NAME, level=logging.INFO) as logger:
add_email_marketing_cookies(None, response=response, user=self.user) add_email_marketing_cookies(None, response=response, user=self.user)
logger.check( logger.check(
(LOGGER_NAME, 'INFO', cookie_log),
(LOGGER_NAME, 'INFO', (LOGGER_NAME, 'INFO',
'Started at {start} and ended at {end}, time spent:{delta} milliseconds'.format( 'Started at {start} and ended at {end}, time spent:{delta} milliseconds'.format(
start=datetime.datetime.now().isoformat(' '), start=datetime.datetime.now().isoformat(' '),
...@@ -121,6 +119,28 @@ class EmailMarketingTests(TestCase): ...@@ -121,6 +119,28 @@ class EmailMarketingTests(TestCase):
self.assertEquals(response.cookies['sailthru_hid'].value, "test_cookie") self.assertEquals(response.cookies['sailthru_hid'].value, "test_cookie")
@patch('email_marketing.signals.SailthruClient.api_post') @patch('email_marketing.signals.SailthruClient.api_post')
def test_get_cookies_via_sailthu(self, mock_sailthru):
cookies = {'cookie': 'test_cookie'}
mock_sailthru.return_value = SailthruResponse(JsonResponse({'keys': cookies}))
post_parms = {
'id': self.user.email,
'fields': {'keys': 1},
'vars': {'last_login_date': datetime.datetime.now().strftime("%Y-%m-%d")},
'cookies': {'anonymous_interest': 'cookie_content'}
}
expected_cookie = get_email_cookies_via_sailthru.delay(self.user.email, post_parms)
mock_sailthru.assert_called_with('user',
{'fields': {'keys': 1},
'cookies': {'anonymous_interest': 'cookie_content'},
'id': TEST_EMAIL,
'vars': {'last_login_date': ANY}})
self.assertEqual(cookies['cookie'], expected_cookie.result)
@patch('email_marketing.signals.SailthruClient.api_post')
def test_drop_cookie_error_path(self, mock_sailthru): def test_drop_cookie_error_path(self, mock_sailthru):
""" """
test that error paths return no cookie test that error paths return no cookie
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment