Skip to content

Commit 527060e

Browse files
authored
Add serverless config (#75)
* fix: Potential conflict with duplicate Notification model * fix: Potential related_name clash for custom models *Make django_json_field optional (Suppress warnings) * Add `pusher` provider * docs: Update documentation * feat: Producers and Consumers * feat: Add serverless config
1 parent 37b9339 commit 527060e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+740
-661
lines changed

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
# ignore = E226,E302,E41
3+
max-line-length = 88

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ htmlcov/
1111
.coverage.*
1212
coverage.xml
1313
*.cover
14+
node_modules/

.pycodestyle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pycodestyle]
2+
max-line-length = 88

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,7 @@ deploy:
8484
tags: true
8585
distributions: sdist bdist_wheel
8686
repo: danidee10/django-notifs
87+
88+
89+
services:
90+
- redis
-16.7 KB
Loading

docs/advanced-usage.rst

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,39 @@ Advanced usage
44
.. _documentation: https://channels.readthedocs.io/en/stable/index.html
55
.. _channels deployment documentation: https://channels.readthedocs.io/en/stable/deploying.html
66

7+
Tentative Notifications
8+
--------------------------------
9+
10+
A tentative notification is a conditional notification that should only be sent if a criteria is met.
11+
12+
An example is sending a notification if a user hasn't read a chat message in 30 minutes (as a reminder).
13+
14+
You can acheive this by combining the ``countdown`` functionality with a custom provider::
15+
16+
# delay notification for 30 minutes
17+
notify(**kwargs, countdown=1800)
18+
19+
Custom provider::
20+
21+
from notifications.utils import get_notification_model
22+
from notifications.providers import BaseNotificationProvider
23+
24+
class DelayedNotificationProvider(BaseNotificationProvider):
25+
26+
name = 'delayed_notifier'
27+
28+
def send(self, payload):
29+
notification_id = self.payload['notification_id']
30+
31+
notification = get_notification_model().objects.get(id=self.notification_id)
32+
if notification.read:
33+
return
34+
35+
# send the notification
36+
37+
In this example, we abort the notification if the notification has been read when the provider is executed.
38+
39+
740
WebSockets
841
---------------------
942

@@ -42,37 +75,22 @@ Notification channels
4275
---------------------
4376
A simple WebSocket channel is provided:
4477

45-
- notifications.channels.WebSocketChannel
46-
47-
This channel simply delivers notifications to the ``settings.NOTIFICATIONS_WEBSOCKET_EVENT_NAME`` group.
48-
49-
Add the channel to ``settings.NOTIFICATION_CHANNELS``::
50-
51-
NOTIFICATION_CHANNELS = {
52-
'websocket': 'notifications.channels.WebSocketChannel'
53-
}
78+
``notifications.channels.DjangoWebSocketChannel``
5479

5580
Sample usage::
5681

57-
from notifications import default_settings as notifs_settings
58-
...
59-
6082
notif_args = {
61-
'source': user,
62-
'source_display_name': user.get_full_name(),
63-
'category': 'MESSAGE', 'action': 'Sent',
64-
'obj': obj.id,
65-
'short_description': 'You a new message', 'silent': True,
66-
'extra_data': {
67-
notifs_settings.NOTIFICATIONS_WEBSOCKET_URL_PARAM: chat_session.uri,
68-
'message': chat_session_message.to_json()
83+
...
84+
extra_data: {
85+
'context': {
86+
'channel_layer': 'default',
87+
'destination': 'group or channel_name',
88+
'message': {'text': 'Hello world'}
89+
}
6990
}
7091
}
7192
notify(**notif_args, channels=['websocket'])
7293

73-
``notifs_settings.NOTIFICATIONS_WEBSOCKET_URL_PARAM`` is a required key. You can also override it in ``settings.py``
74-
and reference it through ``django.conf.settings.NOTIFICATIONS_WEBSOCKET_URL_PARAM``
75-
7694

7795
Running the WebSocket server
7896
----------------------------
@@ -91,9 +109,9 @@ You listen to notifications by connecting to the WebSocket URL.
91109

92110
The default URL is ``http://localhost:8000/<settings.NOTIFICATIONS_WEBSOCKET_URL_PARAM>``
93111

94-
To connect to a WebSocket room (via JavaScript) for a user ``danidee`` you'll need to connect to::
112+
To connect to a WebSocket room (via JavaScript) for a user ``john_doe`` you'll need to connect to::
95113

96-
var websocket = new WebSocket('ws://localhost:8000/danidee')
114+
var websocket = new WebSocket('ws://localhost:8000/john_doe')
97115

98116
You can always change the default route by Importing the ``notifications.consumers.DjangoNotifsWebsocketConsumer``
99117
consumer and declaring another route. If you decide to do that, make sure you use the
@@ -125,12 +143,10 @@ if you don't make use of the standard Authentication backend.
125143
Testing and Debugging
126144
---------------------
127145

128-
django-notifs comes with an inbuilt console delivery channel that just prints out the notification arguments::
129-
130-
131-
NOTIFICATIONS_CHANNELS = {
132-
'console': 'notifications.channels.ConsoleChannel'
133-
}
146+
django-notifs comes with an inbuilt ``'console'`` provider that just prints out the notification payload::
134147

148+
class MyNotificationChannel:
149+
providers = ['console']
150+
...
135151

136-
This can be helpful during development where you don't want notifications to be delivered.
152+
This can be helpful during development when it's used with the Synchronous backend.

docs/backends.rst

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ Backends
44
.. _Celery settings in the repo: https://github.com/danidee10/django-notifs/blob/master/notifs/settings.py
55
.. _django-rq: https://github.com/rq/django-rq
66
.. _django-rq documentation: https://github.com/rq/django-rq
7+
.. _Serverless documentation for AWS: https://www.serverless.com/framework/docs/providers/aws
8+
.. _lambda worker repository: https://github.com/danidee10/django-notifs-lambda-worker
79

8-
The primary function of **a delivery backend** is to execute the code of the delivery channels.
9-
*Unlike delivery channels, you can only use one delivery backend at the same time.*
10+
The primary function of **a delivery backend** is to execute the code of the delivery channels and providers.
11+
*Unlike notification channels, you can only use one delivery backend at a time.*
1012

1113

1214
Celery
@@ -20,11 +22,11 @@ Enable it by setting ``NOTIFICATIONS_DELIVERY_BACKEND`` to ``notifications.backe
2022

2123
Run celery with the command::
2224

23-
celery -A yourapp worker -l info -Q django_notifs
25+
celery -A yourapp worker -l info -Q django-notifs
2426

2527
Whenever a notification is created, it's automatically sent to celery and processed.
2628

27-
**Make sure you see the queue and task (notifications.backends.celery.send_notification) in the terminal**
29+
Make sure you see the queue and task (``notifications.backends.celery.consume``) in the terminal.
2830

2931
.. image:: _static/images/django-notifs-celery.png
3032

@@ -105,6 +107,46 @@ Finally start the rq worker with::
105107
See the `django-rq documentation`_ for more details
106108

107109

110+
AwsLambda (with SQS)
111+
--------------------
112+
113+
The setup for this backend is more involved but it's probably the cheapest and most scalable backend to use in production
114+
because the heavylifting and execution environment is handled by AWS.
115+
116+
set ``NOTIFICATIONS_DELIVERY_BACKEND`` to ``notifications.backends.AwsSqsLambda``
117+
118+
Clone the `lambda worker repository`_ and run::
119+
120+
npm install
121+
122+
The ``sqs-lambda-worker`` folder includes four files that are of interest:
123+
124+
``.env.example``
125+
126+
You can use this file (after renaming it to ``.env``) to configure the environment variables for the autogenerated Lambda function.
127+
You can replace this step by:
128+
- Configuring the environment variables in your CI/CD environment **(Recommended)**
129+
- Exporting them in the current shell.
130+
This is useful if you want to test the serverless deployment locally before moving it to your CI/CD
131+
132+
``requirements.txt``
133+
134+
In order to keep the lambda function as lean as possible,
135+
you have to explicitly declare the requirements that are necessary
136+
for the lambda function. New providers (and their dependencies) are continuously added to django-notifs
137+
so it's not adviseable to install dependencies for providers that you don't need because this could impact
138+
the startup time of your Lambda function.
139+
140+
``serverless.yml``
141+
142+
The Serverless file. It contains a blueprint that deploys the simplest configuration possible but the configuration options
143+
are endless. see the `Serverless documentation for AWS`_ for more information.
144+
145+
``settings.py``
146+
147+
Declare the Django settings for the lambda function
148+
149+
108150
Synchronous
109151
-----------
110152
This is the default backend that sends notifications synchronously.

docs/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555

5656

5757
# Cusotm settings
58-
source_suffix = ['.rst', '.md']
58+
source_suffix = '.rst'
5959

6060
# Logo
6161
# html_logo = '_static/images/django-notifs.png'
62+
pygments_style = 'sphinx'

docs/configuration.rst

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,6 @@ This setting is used override the default database Model for saving notification
1111
but it can be useful if you're trying to integrate django-notifs into an existing project that already has it's own Notificaiton model
1212

1313

14-
``NOTIFICATIONS_CHANNELS``
15-
--------------------------
16-
17-
``Default={}``
18-
19-
A dictionary of notification channels.
20-
21-
**Keys:** The softname of the notification channel which is used in your code
22-
23-
**Values:** The path to the notification channel's class.
24-
25-
Example::
26-
27-
NOTIFICATIONS_CHANNELS = {
28-
'console': 'notifications.channels.ConsoleChannel'
29-
}
30-
31-
django-notifs comes with an inbuilt console delivery channel that just prints out the notification arguments
32-
33-
3414

3515
``NOTIFICATIONS_DELIVERY_BACKEND``
3616
----------------------------------
@@ -100,6 +80,6 @@ In most cases, you don't need to change this setting.
10080

10181
``Default = 'room_name'``
10282

103-
The WebSocket URL param name. This setting **MUST** be used in the ``notify`` method's ``extra_data`` dictionary.
83+
The WebSocket URL param name.
10484
It's also used to construct the WebSocket URL.
10585
See the :ref:`Advanced usage <Notification channels>` section for more information.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ Contents
1414
usage
1515
configuration
1616
backends
17+
providers
1718
advanced-usage

0 commit comments

Comments
 (0)