Repository: mercadona/rele
Pull request #47 (2019-06-12 13:08:40)

Subscriber prefix param
### :tophat: What?

Use custom value as prefix to any subscription instead of static project name.

### :thinking: Why?

Small iteration in order to remove completely Django settings usage.



Patch:
diff --git a/README.md b/README.md
index aeb2ef8..7b43004 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,9 @@ INSTALLED_APPS = [
 You'll also need to set up two variables with the Google Cloud credentials:
 `RELE_GC_CREDENTIALS` and `RELE_GC_PROJECT_ID`.
 
+You can use `RELE_SUB_PREFIX` to add a prefix to all your subscription names, for
+example, with your project name.
+
 NOTE: Ensure that [`CONN_MAX_AGE`](https://docs.djangoproject.com/en/2.2/ref/settings/#conn-max-age)
 is set to 0 in your worker. The Django default value is 0.
 
diff --git a/rele/management/commands/runrele.py b/rele/management/commands/runrele.py
index 44d9a8c..29fe7c7 100644
--- a/rele/management/commands/runrele.py
+++ b/rele/management/commands/runrele.py
@@ -52,6 +52,8 @@ class Command(BaseCommand):
             for attr_name in dir(sub_module):
                 attribute = getattr(sub_module, attr_name)
                 if isinstance(attribute, Subscription):
+                    if settings.RELE_PREFIX and not attribute.prefix:
+                        attribute.set_prefix(settings.RELE_SUB_PREFIX)
                     subscriptions.append(attribute)
         return subscriptions
 
diff --git a/rele/subscription.py b/rele/subscription.py
index 6d2cee1..5bc5c20 100644
--- a/rele/subscription.py
+++ b/rele/subscription.py
@@ -3,20 +3,29 @@ import logging
 import time
 
 from django import db
-from django.conf import settings
 
 logger = logging.getLogger(__name__)
 
 
 class Subscription:
 
-    def __init__(self, func, topic, suffix=None):
+    def __init__(self, func, topic, prefix='', suffix=''):
         self._func = func
         self.topic = topic
-        self.project_name = settings.BASE_DIR.split("/")[-1]
-        self.name = f'{self.project_name}-{topic}'
-        if suffix:
-            self.name += f'-{suffix}'
+        self._prefix = prefix
+        self._suffix = suffix
+
+    @property
+    def name(self):
+        name_parts = [self._prefix, self.topic, self._suffix]
+        return '-'.join(filter(lambda x: x, name_parts))
+
+    @property
+    def prefix(self):
+        return self._prefix
+
+    def set_prefix(self, prefix):
+        self._prefix = prefix
 
     def __call__(self, data, **kwargs):
         self._func(data, **kwargs)
@@ -66,7 +75,7 @@ class Callback:
 
     def _build_data_metrics(self, status, start_processing_time):
         result = {
-            'agent': self._subscription.project_name,
+            'agent': self._subscription.prefix or 'rele',
             'topic': self._subscription.topic,
             'status': status,
             'subscription': self._subscription.name,
@@ -80,7 +89,7 @@ class Callback:
         return result
 
 
-def sub(topic, suffix=None):
+def sub(topic, prefix=None, suffix=None):
     """Decorator function that makes declaring a PubSub Subscription simple.
 
     The Subscriber returned will automatically create and name
@@ -98,6 +107,10 @@ def sub(topic, suffix=None):
 
     Usage::
 
+        @sub(topic='lets-tell-to-alice', prefix='shop')
+        def bob_purpose(data, **kwargs):
+             pass
+
         @sub(topic='lets-tell-everyone', suffix='sub1')
         def purpose_1(data, **kwargs):
              pass
@@ -107,13 +120,15 @@ def sub(topic, suffix=None):
              pass
 
     :param topic: string The topic that is being subscribed to.
-    :param suffix: string An options suffix to the subscription name.
+    :param prefix: string An optional prefix to the subscription name.
+                   Useful to namespace your subscription with your project name.
+    :param suffix: string An optional suffix to the subscription name.
                    Useful when you have two subscribers in the same project that
                    are subscribed to the same topic.
     :return: Subscription
     """
 
     def decorator(func):
-        return Subscription(func=func, topic=topic, suffix=suffix)
+        return Subscription(func=func, topic=topic, prefix=prefix, suffix=suffix)
 
     return decorator


Test patch:
diff --git a/tests/settings.py b/tests/settings.py
index 8b4105e..900431a 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -31,6 +31,8 @@ RELE_GC_CREDENTIALS = service_account.Credentials.from_service_account_file(
     f'{BASE_DIR}/tests/dummy-pub-sub-credentials.json'
 )
 
+RELE_SUB_PREFIX = 'rele'
+
 logging_config.dictConfig({
     'version': 1,
     'disable_existing_loggers': False,
diff --git a/tests/test_subscription.py b/tests/test_subscription.py
index 23058f9..20ea3a8 100644
--- a/tests/test_subscription.py
+++ b/tests/test_subscription.py
@@ -9,12 +9,18 @@ from rele import Callback, Subscription, sub
 logger = logging.getLogger(__name__)
 
 
-@sub(topic='some-cool-topic')
+@sub(topic='some-cool-topic', prefix='rele')
 def sub_stub(data, **kwargs):
     logger.info(f'I am a task doing stuff with ID {data["id"]} '
                 f'({kwargs["lang"]})')
 
 
+@sub(topic='some-fancy-topic')
+def sub_fancy_stub(data, **kwargs):
+    logger.info(f'I used to have a prefix, but not anymore, only {data["id"]}'
+                f'id {kwargs["lang"]}')
+
+
 class TestSubscription:
 
     def test_subs_return_subscription_objects(self):
@@ -22,6 +28,11 @@ class TestSubscription:
         assert sub_stub.topic == 'some-cool-topic'
         assert sub_stub.name == 'rele-some-cool-topic'
 
+    def test_subs_without_prefix_return_subscription_objects(self):
+        assert isinstance(sub_fancy_stub, Subscription)
+        assert sub_fancy_stub.topic == 'some-fancy-topic'
+        assert sub_fancy_stub.name == 'some-fancy-topic'
+
     def test_executes_callback_when_called(self, caplog):
         res = sub_stub({'id': 123}, **{'lang': 'es'})
 
@@ -104,7 +115,7 @@ class TestCallback:
 
     def test_log_does_not_ack_called_message_when_execution_fails(
             self, caplog, message_wrapper):
-        @sub(topic='some-cool-topic')
+        @sub(topic='some-cool-topic', prefix='rele')
         def crashy_sub_stub(data, **kwargs):
             raise ValueError('I am an exception from a sub')
 
diff --git a/tests/test_worker.py b/tests/test_worker.py
index 607433d..b718c5e 100644
--- a/tests/test_worker.py
+++ b/tests/test_worker.py
@@ -7,7 +7,7 @@ from rele import Subscriber, Worker, sub
 from . import settings
 
 
-@sub(topic='some-cool-topic')
+@sub(topic='some-cool-topic', prefix='rele')
 def sub_stub(data, **kwargs):
     print(f'I am a task doing stuff.')