Erste Schritte mit SignalR unter Azure mit JavaScript

Neulich bereiteten sich einige gute Entwickler in meinem Unternehmen darauf vor, eine Statusaktualisierungsseite einzurichten. Wir hatten es ausgiebig getestet, aber jetzt wollten wir es maßstabsgetreu herausbringen.

Ich war besorgt über die Abhängigkeit von einem API-Server, der kürzlich aktiv war. Wir haben die Hauptursache für unsere Probleme auf der API-Seite nicht ermittelt, und diese Anwendung verwendet Polling - das heißt, sie fragt die API ständig nach neuen Daten. Wenn diese API ausfällt, nimmt sie unsere App mit und die erhöhte Auslastung unserer App kann die Probleme, die wir sehen, verschlimmern.

Touristen in Irland warten vielleicht auf eine Nachricht

Eine Möglichkeit , von Polling zu Schritt weg ist SignalR zu integrieren, eine ständige Verbindung Werkzeug , dass Anwendungen WebSockets und verwandte Technologien auf Server ermöglichen Push - Updates für die Kunden.

Die Technologie ist in .NET geschrieben, und die meisten Dokumentationen im Internet verwenden C #. Dieses Tutorial behandelt eine grundlegende JavaScript-Implementierung.

Was tut es?

Open-Source-SignalR stellt eine dauerhafte Verbindung zwischen einem Client und einem Server her. Es werden zuerst Websockets, dann Longpolling und andere Technologien verwendet, wenn keine Websockets verfügbar sind.

Sobald der Client und der Server eine Verbindung hergestellt haben, kann SignalR verwendet werden, um Nachrichten an den Client zu "senden". Wenn der Client diese Nachrichten empfängt, kann er Funktionen wie das Aktualisieren eines Geschäfts ausführen.

Das häufigste Beispiel für Websockets ist eine Chat-App. Dem Benutzer müssen neue Daten angezeigt werden, ohne dass er die Seite aktualisieren muss. Wenn Ihr Server jedoch Aktualisierungen zum Ändern von Daten erhält, die Sie einem Client anzeigen müssen, ist dies möglicherweise der richtige Dienst für Sie.

SignalR auf der Azure-Plattform

Möglicherweise, weil es von Microsoft entwickelt wurde, hat SignalR eine sehr saubere Integration in die Azure-Cloud-Plattform. Wie bei anderen Funktions-Apps erstellen Sie einen "In" -Trigger und eine "Out" -Bindung für das Senden von Nachrichten.

Kosten

Da ich mich in meinem Unternehmen als erster mit dieser Technologie in großem Maßstab befasst habe, musste ich mich ein wenig mit den Kosten für diesen Service befassen. Azure berechnet für eine "Einheit" des SignalR-Dienstes etwa 50 US-Dollar pro Monat - 1000 gleichzeitige Verbindungen und eine Million Nachrichten pro Tag. Es gibt auch einen kostenlosen Service für Spieler oder kleine Unternehmen.

Es war wirklich gut, dass ich mich in diese Zahlen vertieft habe, wie Sie unten sehen werden.

Erstellen Sie einen SignalR-Hub

Lass uns anfangen. Wir benötigen einen SignalR-Hub, zwei Funktions-Apps und Client-Code, um unsere Web-App zu ergänzen.

Gehen Sie zu SignalR -> Fügen Sie Ihre Daten hinzu und füllen Sie sie aus. Es dauert eine Sekunde, bis der Mitarbeiter Ihren Service erstellt hat. Stellen Sie sicher, dass Sie dem Dienst einen anständigen Ressourcennamen geben, da Sie ihn mit den übrigen Apps verwenden. Greifen Sie auch nach Schlüsseln -> Verbindungszeichenfolge, um sie in unserer Bindung zu verwenden.

Einrichten von SignalR in Azure

Erstellen Sie Ihre Funktions-App zum Senden von SignalR-Nachrichten

Da wir mit Azure arbeiten, werden wir Funktions-Apps für die Schnittstelle mit SignalR erstellen. Ich habe vor einiger Zeit einen Blog-Beitrag über Azure-Funktions-Apps geschrieben.

In diesem Tutorial wird davon ausgegangen, dass Sie bereits wissen, wie Sie mit Funktions-Apps arbeiten. Natürlich können Sie mit diesen Bibliotheken ohne Bindungszauber arbeiten, aber Sie müssen den .NET-Code selbst übersetzen!

Die Verbindungs-App

Das erste, was wir brauchen, ist eine Möglichkeit für Kunden, die Erlaubnis zum Herstellen einer Verbindung zu unserem SignalR-Dienst anzufordern. Der Code für diese Funktion könnte nicht grundlegender sein:

module.exports = function (context, _req, connectionInfo) { context.res = { body: connectionInfo } context.done() } 

Die Magie geschieht alles in den Bindungen, in denen wir unseren SignalR-Service in Anspruch nehmen. Der Auslöser ist eine HTTP-Anfrage, die unser Client aufrufen kann.

{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "req", "methods": ["get"] }, { "type": "signalRConnectionInfo", "name": "connectionInfo", "hubName": "your-signalr-service-name", "connectionStringSetting": "connection-string", "direction": "in" } ] } 

Der Client-Code

Um auf diese Methode zuzugreifen, ruft unser Client Folgendes auf:

import * as signalR from '@microsoft/signalr' const { url: connectionUrl, accessToken } = await axios .get(url-to-your-connection-app) .then(({ data }) => data) .catch(console.error) 

Unsere Funktions-App gibt ein urlund zurück accessToken, mit dem wir uns dann mit unserem SignalR-Dienst verbinden können. Beachten Sie, dass wir die Bindung mit dem hubNameunseres SignalR-Dienstes erstellt haben. Dies bedeutet, dass Sie mehrere Verbindungen zu verschiedenen Hubs in einem Client haben können.

Der Rundfunkdienst

Jetzt können wir mit dem Senden von Nachrichten beginnen. Wieder beginnen wir mit der Funktions-App. Es nimmt einen Trigger auf und gibt eine SignalR-Nachricht aus.

Ein Auslöser kann ein anderer sein, bei dem eine Nachricht, ein Ereignis von einem Ereignis-Hub oder ein anderer von Azure unterstützter Auslöser veröffentlicht wird. Ich muss Datenbankänderungen auslösen.

{ "bindings": [ { "type": "cosmosDBTrigger", "name": "documents", "direction": "in", [...] }, { "type": "signalR", "name": "signalRMessages", "hubName": "your-signalr-service-name", "connectionStringSetting": "connection-string", "direction": "out" } ] } 

Und der Code. Wieder ganz einfach.

module.exports = async function (context, documents) { const messages = documents.map(update => { return { target: 'statusUpdates', arguments: [update] } }) context.bindings.signalRMessages = messages } 

SignalR-Nachrichten nehmen ein targetund argumentsObjekt. Sobald Ihre Trigger ausgelöst werden, ist dies alles, was Sie benötigen, um mit SignalR auf dem Server zu beginnen! Microsoft hat uns das alles sehr leicht gemacht.

Der Client-Code

Auf der Client-Seite sind die Dinge etwas komplexer, aber nicht unüberschaubar. Hier ist der Rest des Client-Codes:

const connection = new signalR.HubConnectionBuilder() .withUrl(connectionUrl, { accessTokenFactory: () => accessToken }) // .configureLogging(signalR.LogLevel.Trace) .withAutomaticReconnect() .build() connection.on('statusUpdates', data => { // do something with the data you get from SignalR }) connection.onclose(function() { console.log('signalr disconnected') }) connection.onreconnecting(err => console.log('err reconnecting ', err) ) connection .start() .then(res => // Potential to do something on initial load) .catch(console.error) 

Wir verbrauchen das connectionUrlund accessTokenwir haben es früher von der Verbindungsfunktion erhalten und bauen dann unsere Verbindung mit diesen Werten auf.

Dann hören wir Nachrichten mit dem gemeinsam genutzten Schlüssel ab (für mich ist es das statusUpdates) und stellen Handler für Funktionen zum Schließen und erneuten Verbinden bereit.

Schließlich starten wir die Verbindung. Hier können wir eine anfängliche Ladefunktion bereitstellen. Ich brauchte eine, um die Anfangsdaten abzurufen und den aktuellen Status anzuzeigen. Wenn Sie eine Chat-App erstellen, müssen Sie möglicherweise hier erste Nachrichten abrufen.

Dies ist (fast, vielleicht) alles, was Sie brauchen, um mit SignalR on Azure in JavaScript zu beginnen!

Umfang nach Benutzer

Aber vielleicht müssen Sie, wie ich, viele Nachrichten an viele Benutzer senden.

Als ich dies zum ersten Mal in Produktion nahm, habe ich bei einer Untergruppe von Benutzern jede Verbindung mit jedem einzelnen Update gesprengt. Da der Client-Code die Nachrichten erfassen kann, die er abhört, habe ich so etwas verwendet, statusUpdates-${userId}damit der Client nur seine eigenen Updates sieht.

That could work just fine if you have very low volume, and the more general one is great if everybody in your system needs the same message. But the status I work with is particular to an individual.

800.000 SignalR-Nachrichten, die von der Azure-Plattform gesendet wurden

Remember how Azure charges per "unit" and each unit has one million messages? I hit that during a few hours of testing this during a not-busy time.

Azure counts each message SignalR has to send as one message. That is, if five connections are hooked up to your hub and you send ten messages, that counts as 50, not 10. This was a surprise to me, and also required a couple more hours of research.

We can scope our SignalR function code to send only to certain users. First, we update the connection app to accept userId as a query param:

 { "type": "signalRConnectionInfo", "name": "connectionInfo", "userId": "{userId}", "hubName": "your-signalr-service-name", "connectionStringSetting": "connection-string", "direction": "in" } 

Then we update the broadcasting function to send only to that user:

const messages = documents.map(update => { return { target: 'statusUpdates', userId: update.user.id, arguments: [update] } }) 

The broadcasting service won't know who has connected, so you'll need to trigger it with something that has access to a unique ID that the client will also have access to.

The client code simply passes in the userId as a query param:

const { url: connectionUrl, accessToken } = await axios .get(`${url-to-your-connection-app}&userId=${userId}`) .then(({ data }) => data) .catch(console.error) 

I swear to you, the only place on the entire internet I found to let me know how to request a connection using the userId was an answer on this Stack Overflow question.

The internet is amazing, and JavaScript Azure docs are hard to come by.

Resources

  • SignalR Javascript client docs from Microsoft
  • Configuring Users and Groups when sending SignalR messages -

    examples in C# but you can maybe figure out how the JavaScript client is going to behave and make some educated guesses.

  • SignalR Service bindings for Azure Functions
  • Client API
  • Working with Groups in SignalR
  • Lernprogramm: Azure SignalR Service-Authentifizierung mit Azure-Funktionen

Dieser Beitrag erschien ursprünglich auf wilkie.tech.