...
In early discussion about notifications for Discussion Forum, we recognize that this kind of notifications is different from the Synapse Email Services that we have. In this case, users may want to subscribe to a topic or an object in Synapse and received notifications when something changed within this topic/ object. When receiving notifications about the events, user may or may not want to take any action. Users should also be able to choose the type of notifications they would like to receive, and be able to unsubscribe to a topic/ object and still receive notifications about events that happen around another topic/ object.
Approach
Image Removed
When an event happens on a subscribable object, a message will be pushed to the object topic. From there, the message will be forwarded to each subscriber topic. Each subscriber has a queue of events that the subscriber is listening to. A worker will periodically check this queue and combine events. The worker may send the combined event message to the Synapse Email Services to send an email to the user, or push the combined message back to the queue. From the Web UI, the UI can make request to see all events.
The arrow represents the direction of data flow.
AWS Limitations and Restrictions
AWS Simple Notification Services
- 10 milion subscriptions per topic
- 100,000 topics per account (may request to increase)
- 256 KB text in XML, JSON or unformatted
We will need a topic for each object, and a topic for each user. The number of object could exceed the topic limit in AWS.
A solution for this problem is removing a topic once the object become inactive. With this approach, we need to make sure that # of active objects + # of users < 100,000. (Note that we also use AWS SNS for other features in Synapse.)
AWS Simple Queue Services
- unlimited number of queue
- unlimited number of message
- message exists in a queue for 1-2 weeks
- 12 hours max for message visibility
We will need a queue for each user. However, since we have unlimited number of queue, this won't be a problem.
Subscribe/ Unsubscribe
A moderator is automatically subscribed to all threads in his forum. However, he role is to make sure that everything is going well. He recognized a thread that has healthy discussion and doesn't want to be notified by this thread anymore. He chooses to unsubscribe to this thread, but still subscribe to all other threads and any new threads in this forum.
There are 2 approaches for this problem:
- When a user subscribe to a forum, automatically subscribe the user to all threads in that forum. When a new thread is added, add a subscription to all subscribers of the forum. When a user unsubscribe to a thread, remove a single thread subscription and maintain the global (forum) subscription.
Pros: Only store the events that a subscriber subscribe to in AWS.
Cons: Need more space to keep track of what threads a user subscribe to. - Only keep track of user's global subscription. When a user unsubscribe to a thread, add the thread to user's black list. Before sending out email notification or displaying events, filter out the events that are in the user's black list.
Pros: Only store the subscriptions rules in the DB.
Cons: Store unused events in AWS.
We will pick one approach and move forward. Depending on what other problems that come up during the implementation, we may switch to a different approach.
Problems that need solution
Inactive object/ topic
How do we know if an AWS topic is inactive?
If there is no ways for us to check the AWS topic's inactivity, how do we keep track of the object's inactivity?
Staging vs Prod
When a new thread created in staging, do we send notification for all users that subscribe to the forum?
If so, should we point them to staging or prod? If we point them to staging, they will see the new thread, but may be confused between staging and prod. If we point them to prod, they will not be able to see the new thread and may think that Synapse is broken.
Models
Image Removed
API
...
Mockups
User has not subscribe/ watch this thread and this forum.
Image Added
User who subscribed/ watching this thread and this forum.
Image Added
User logged in to unsubscribe/ stop watching this thread.
Image Added
Models
Image Added
API
| Action | Intended User | URI | Method | Request Params | Request Body | Response Body |
---|
1 | subscribe to |
an objecta topic | Synapse users who has READ permission on the object | / |
subscriptions Subscription | all subscriptionssubscriptions a user has for a given list of topics | Synapse users | /subscription/ |
subscriptionsGETlimit, offset SubscriptionPage | retrieve single subscriptiontopic | Synapse users who created this subscription | / |
subscriptionsobjectId}/type/{objectTypeGET | | | Subscriptionunsubscribe to an objectretrieve all subscriptions for a user | Synapse users |
who subscribed to the objectsubscriptions/unsubscribe/{objectId}/type/{objectType}DELETE | | | | 5 | change notification method | Synapse users who subscribed to the object | /subscriptions | PUT | | Subscriptionsubscription/all | GET | limit, offset, objectType (optional) |
| SubscriptionPagedResults |
5 | retrieve a subscription | Synapse users who created this subscription | /subscription/{subscriptionId} | GET |
|
| Subscription |
6 |
get all notificationsretrieve subscribers for a topic | Synapse users | / |
notifications7 | get all notifications for a single objectGET | filter(NO_FILTER, UNREAD_ONLY), limit, offset | | NotificationPage | POST | nextPageToken | Topic | SubscriberPagedResults |
7 | retrieve number of subscribers for a topic | Synapse users | / |
notifications{objectId}/type/{objectType}GET | limit, offset | | NotificationPage | 8 | mark a notification as readsubscribers/count | POST |
| Topic | SubscriberCount |
8 | subscribe to all topics with the same SubscriptionObjectType | Synapse users | / |
notifications/{notificationId}/readPUT | | | | 9 | get event | Synapse users | /events/{eventId}/type/{eventType} | GET | | | Event |
...
subscription/all | POST | objectType |
| Subscription |
SubscriberPagedResults |
---|
String nextPageToken |
List<String> subscribers |
SubscriberCount |
---|
long count |