loading...

Service notifs with Matrix

halfshot profile image Will Hunt ・2 min read
import ...

const log = new Log("MatrixProvider")

export class MatrixProvider {
    private client: any;

    constructor(private matrixConfig: any) {
    }

    Setup() {
        this.client = Matrix.createClient({
            baseUrl: this.matrixConfig.homeserver,
            userId: this.matrixConfig.user_id,
            accessToken: this.matrixConfig.access_token
        });
    }

    SendMessage(roomid: string, body: string): Promise<any> {
        return this.client.sendHtmlMessage(roomid, striptags(body), body);
    }
}

This is all the code needed to add to our infrastructure to start sending notifications out to staff on the network for alerts. Matrix is my first choice when needing to send alerts inside a service. It's quick, it's a single HTTP request and you get push for free!

The Problem

The application I am working sends out notifications to 3 groups of people: Admins, Users, and Customers.

  • The admin needs to find out if requests are repeatedly failing in the backend.
  • The users need to find out if a customer has filled in a form or sent a review.
  • The customers need to be notified if there is a change to their assigned products.

The biggest messaging problem I have seen in services I have worked on is that the apps each have their own set of rules for notifying, usually hidden in some config. If you change a group, or a name somewhere you might find yourself rewriting a lot of configuration files -- and that's to say nothing of expandability beyond your standard sendmail setup.

The Solution

A single service, a single new message queue type and a single mapping document inside our DB.

The service is simple and elegant. It connects to CouchDB, reads a mapping document and listens for changes (a cool feature of CDB).

A typical mapping document:

{
    "_id":"ccs.notifications",
    "_rev":"xyz",
    "mapping": {
        "#admins": { 
            "matrix": ["!PxMWbvomtRqGOTsaDK:half-shot.uk"],
            "email": ["will@half-shot.uk"]
            "twitter":..,
            "slack":..,
         }
    }
}

When a message comes in, we map content.to to a mapping field (which must start with a #). The mapping is picked up, we traverse and send a notification out one or more rooms. You can then trust the Matrix homeserver to deliver it to the right set of users. Potentially in the future, we may check the status of read receipts to nag the user by email if they have not checked their Riot app.

Result in Riot

In the future we could expand on this to include E2E messaging for customers, so they can be sure the message is coming from the correct service and not from an attacker -- should an access token get leaked.

Anyway, this is a quick post about a rather elegant solution to sending notifications.

Discussion

pic
Editor guide