Notification is an implementation of an HTTP-based notification web service, based on Yammer's Streamie service. This project was developed using:
Similar to Yammer's implementation, the Notification service relies on K-Sortable Unique Identifers (KSUID) that are used to resolve conflicts within Riak. The IDs are also used to provide a sorting order for the notifications so the newest notifications always appear at the top of a user's notification list. Every unique username can store up to 1000 notifications before the older notifications are aged out of the system.
Notifications are stored in the notifications
bucket in Riak. The service also stores a cursor representing the most recent seen notification for that user. Cursors are stored in the cursors
bucket in Riak. A cursor looks like:
{"key": "test-notifications", "value": "0ujsszwN8NRY24YaXiTIE2VWDTS"}
Where the username is test
, the cursor name is notifications
and the value of the cursor is 0ujsszwN8NRY24YaXiTIE2VWDTS
.
When a user retrieves their list of notifications, the service will update the value of their cursor to the most recent notification.
The Notification service supports the concept of "rollups" using rules. Rules are created by using the API (see below).
# Roll-up Rules
rules:
new-follower:
max-size: 9
max-duration: 12 hours
like:
max-duration: 3 hours
match-on: message_id
This would mean, for the new-follower
category, roll up to a maximum of 9 notifications as long as there are no more than 12 hours between the first and last notifications. For the like
category, roll up notifications within a 3 hour time window but they must have a matching message_id
property value in each notification. As with Yammer's implementation, notifications are first partitioned between the seen and unseen prior to rolling up the notifications. This prevents pulling forward a notification that has already been seen and showing it to the user in a grouping of unseen notifications.
To build this code locally, clone the repository then build the jar:
git clone https://github.com/smoketurner/notification.git
cd notification
./mvnw package
java -jar notification-application/target/notification-application-1.3.1-SNAPSHOT.jar server config.yml
The Notification service should be listening on port 8080
(with the Dropwizard administrative interface available at /admin).
To deploy the Notification service into production, it can safely sit behind any HTTP-based load balancer (nginx, haproxy, F5, etc.).
To connect to Riak, configure the cluster behind a load-balancer as generally recommended. In order to support the Notification service automatically retrying Riak requests to separate nodes in the cluster, it is recommended to list each Riak node individually in the configuration file.
NOTE: The notification service provides no authentication or authorization of requests. It is recommended to use a separate service such as Kong or the Amazon API Gateway to authenticate and authorize users.
The Notification service provides RESTful URLs when creating, retrieving and deleting notifications. All of the API paths are in the form of /v1/notifications/<username>
. In the following examples, we'll be using test
as the username.
API documentation is also available via GraphiQL at http://localhost:8080/graphql
.
To create a notification, you can execute a POST
request to the API endpoint specifying category
and message
fields (both are required).
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"category": "new-follower", "message": "You have a new follower"}' \
http://localhost:8080/v1/notifications/test -i
HTTP/1.1 201 Created
Date: Sun, 26 Jul 2015 16:06:10 GMT
Location: http://localhost:8080/v1/notifications/test
Content-Type: application/json;charset=UTF-8
X-Request-Id: 9a3ec8d0-1e00-47de-bb78-609a499849c4
Content-Length: 157
{
"id":"0ujsszwN8NRY24YaXiTIE2VWDTS",
"category":"new-follower",
"message":"You have a new follower",
"created_at":"2015-07-26T16:06:10.970Z"
}
The service will generate a globally unique ID and return it in the response along with the created_at
timestamp.
curl -X GET http://localhost:8080/v1/notifications/test -i
HTTP/1.1 200 OK
Date: Sun, 26 Jul 2015 16:12:11 GMT
Last-Modified: Sun, 26 Jul 2015 16:06:10 GMT
Accept-Ranges: id
Content-Range: id 0ujsszwN8NRY24YaXiTIE2VWDTS..0ujsszwN8NRY24YaXiTIE2VWDTS
Content-Type: application/json;charset=UTF-8
X-Request-Id: ce32a162-483d-4c34-9524-02b7f667704f
Cache-Control: no-cache, no-store, no-transform, must-revalidate
Content-Length: 190
[
{
"id": "0ujsszwN8NRY24YaXiTIE2VWDTS",
"category": "new-follower",
"message": "You have a new follower",
"created_at": "2015-07-26T16:06:10.970Z",
"unseen": true,
"properties": {}
}
]
The service defaults to only returning the 20 most recent notifications at a time. To return more notifications, you can execute a request specifying the Range
HTTP header:
curl -X GET -H "Range: id;max=100" http://localhost:8080/v1/notifications/test -i
If there are more notifications available, the service will include a Next-Range
HTTP response header that you can specify in a Range
header on a subsequent request. This will allow you to paginate through all of the results, up to a 1000 notifications.
To delete individual notifications, you can execute a DELETE
request specifying the notification ID's to delete.
curl -X DELETE "http://localhost:8080/v1/notifications/test?ids=0ujsszwN8NRY24YaXiTIE2VWDTS,0ujsswThIGTUYm2K8FjOOfXtY1K" -i
HTTP/1.1 204 No Content
Date: Sun, 26 Jul 2015 16:34:15 GMT
X-Request-Id: d3b446ea-08b4-4e81-9c13-06c6c372ba46
This endpoint will always return a 204
response code even if the notification ID's don't exist.
To remove all of the notifications for a user, you can execute a DELETE
request without specifying any individual notification IDs.
curl -X DELETE http://localhost:8080/v1/notifications/test -i
HTTP/1.1 204 No Content
Date: Sun, 26 Jul 2015 16:34:15 GMT
X-Request-Id: d3b446ea-08b4-4e81-9c13-06c6c372ba46
This will remove all of the test
user's notifications, their cursor and will always return a 204
response code.
To create or update a rollup rule, you can execute a PUT
request specifying the category of notifications this rule applies to.
curl \
-X PUT \
-H "Content-Type: application/json" \
-d '{"max_size": 9, "max_duration": "12 hours"}' \
http://localhost:8080/v1/rules/new-follower -i
HTTP/1.1 204 No Content
Date: Sun, 26 Jul 2015 16:34:15 GMT
X-Request-Id: d3b446ea-08b4-4e81-9c13-06c6c372ba46
When retrieving notifications, any notifications with the new-follower
category will be rolled up to a maximum of 9 notifications as long as there are no more than 12 hours between the first and last notifications.
curl -X DELETE http://localhost:8080/v1/rules/new-follower -i
HTTP/1.1 204 No Content
Date: Sun, 26 Jul 2015 16:34:15 GMT
X-Request-Id: d3b446ea-08b4-4e81-9c13-06c6c372ba46
curl -X GET http://localhost:8080/v1/rules -i
HTTP/1.1 200 OK
Date: Sun, 26 Jul 2015 16:12:11 GMT
Content-Type: application/json;charset=UTF-8
X-Request-Id: ce32a162-483d-4c34-9524-02b7f667704f
Cache-Control: no-cache, no-store, no-transform, must-revalidate
Content-Length: 190
{
"new-follower": {
"max_size": 3,
"max_duration": "12 hours"
},
"like": {
"max_duration": "3 hours",
"match_on": "message_id"
}
}
Please file bug reports and feature requests in GitHub issues.
Copyright (c) 2018 Smoke Turner, LLC
This library is licensed under the Apache License, Version 2.0.
See http://www.apache.org/licenses/LICENSE-2.0.html or the LICENSE file in this repository for the full license text.