Repository: mdn/kuma

Issue:
SSR Sentry error reporting
At the time of writing, 7 times this has happened:
```
HTTPError: 500 Server Error: Internal Server Error for url: http://ssr/ssr/SPA
  File "django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "newrelic/hooks/framework_django.py", line 544, in wrapper
    return wrapped(*args, **kwargs)
  File "django/views/decorators/cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "django/views/decorators/http.py", line 40, in inner
    return func(request, *args, **kwargs)
  File "ratelimit/decorators.py", line 30, in _wrapped
    return fn(*args, **kw)
  File "kuma/search/views.py", line 34, in search
    return render(request, 'search/react.html', context)
  File "django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "django_jinja/backend.py", line 106, in render
    return mark_safe(self.template.render(context))
  File "newrelic/api/function_trace.py", line 121, in dynamic_wrapper
    return wrapped(*args, **kwargs)
  File "jinja2/environment.py", line 1008, in render
    return self.environment.handle_exception(exc_info, True)
  File "jinja2/environment.py", line 780, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/app/kuma/search/jinja2/search/react.html", line 3, in top-level template code
    {% set query = request.GET.get('q') %}
  File "/app/jinja2/react_base.html", line 103, in top-level template code
    {% block document_head %}{% endblock %}
  File "/app/kuma/search/jinja2/search/react.html", line 20, in block "document_head"
    results)|safe }}
  File "kuma/wiki/templatetags/ssr.py", line 50, in render_react
    return server_side_render(component_name, data)
  File "kuma/wiki/templatetags/ssr.py", line 133, in server_side_render
    response.raise_for_status()
  File "requests/models.py", line 940, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
```
https://sentry.prod.mozaws.net/operations/mdn-prod/issues/6448273/?query=is:unresolved

It's "fine". The SSR service is bound to be imperfect. What's worrying is that there are no Node errors in Sentry. It's just too unlikely that there have been no exceptions in the SSR Node service. 


Discussion:
Perhaps the next action is to try to reproduce an error in the SSR service with the Stage Sentry DSN set as an environment variable. Is it sending stuff?
Note-to-self; the task is to verify that errors inside ssr-server.jsx triggers an error sent to Sentry. 
And if the SSR service throws a 500, back to python `requests.post()` it should not trigger another Sentry error about that. 
https://sentry.prod.mozaws.net/operations/mdn-stage/issues/6842194/?query=is:unresolved did happen from my local deliberate testing. 
For local dev, and docker-compose, it doesn't read from the `.env` file so I manually added it in docker-compose.yml for the `ssr` service. 
In production, it appears to be *configured*. See this search from Papertrail:
<img width="1505" alt="Screen Shot 2019-12-10 at 2 30 49 PM" src="https://user-images.githubusercontent.com/26739/70562113-c6d35780-1b59-11ea-91df-3b24dc2b0d33.png">
Yay!

Resolving patch:
diff --git a/kuma/wiki/templatetags/ssr.py b/kuma/wiki/templatetags/ssr.py
--- a/kuma/wiki/templatetags/ssr.py
+++ b/kuma/wiki/templatetags/ssr.py
@@ -134,11 +134,7 @@ def server_side_render(component_name, data):
         result = response.json()
         return _render(component_name, result['html'], result['script'])
 
-    except requests.exceptions.ConnectionError:
-        print("Connection error contacting SSR server.")
-        print("Falling back to client side rendering.")
-        return client_side_render(component_name, data)
-    except requests.exceptions.ReadTimeout:
-        print("Timeout contacting SSR server.")
+    except requests.exceptions.RequestException as exception:
+        print(f"{exception.__class__} error contacting SSR server.")
         print("Falling back to client side rendering.")
         return client_side_render(component_name, data)


Test patch:
diff --git a/kuma/settings/testing.py b/kuma/settings/testing.py
--- a/kuma/settings/testing.py
+++ b/kuma/settings/testing.py
@@ -85,3 +85,6 @@
 
 # Use a dedicated minio bucket for tests
 ATTACHMENTS_AWS_STORAGE_BUCKET_NAME = 'test'
+
+# Never enabled in tests.
+SENTRY_DSN = None
diff --git a/kuma/wiki/tests/test_ssr.py b/kuma/wiki/tests/test_ssr.py
--- a/kuma/wiki/tests/test_ssr.py
+++ b/kuma/wiki/tests/test_ssr.py
@@ -99,7 +99,8 @@ def test_client_side_render(mock_get_l10n_data, mock_dumps):
 
 @pytest.mark.parametrize('failure_class', [
     requests.exceptions.ConnectionError,
-    requests.exceptions.ReadTimeout])
+    requests.exceptions.ReadTimeout,
+    requests.exceptions.HTTPError])
 @mock.patch('json.dumps')
 @mock.patch('kuma.wiki.templatetags.ssr.get_localization_data')
 def test_failed_server_side_render(mock_get_l10n_data,
@@ -109,7 +110,7 @@ def test_failed_server_side_render(mock_get_l10n_data,
     localization_data = {'catalog': {'s': 't'}, 'plural': None}
     mock_get_l10n_data.side_effect = lambda l: localization_data
     mock_dumps.side_effect = sorted_json_dumps
-    url = '{}/{}'.format(settings.SSR_URL, 'page')
+    url = f'{settings.SSR_URL}/page'
     mock_requests.post(url, exc=failure_class('message'))
     document_data = {'x': 'one', 'y': 2, 'z': ['a', 'b']}
     path = '/en-US/docs/foo'