Sådan kommer du i gang med SignalR på Azure med JavaScript

Forleden var nogle fine udviklere hos mit firma klar til at udrulle en statusopdateringsside. Vi havde testet det grundigt, men nu var vi ved at lægge det ud i målestok.

Jeg var bekymret for dens afhængighed af en API-server, der havde handlet op for nylig. Vi har ikke fundet årsagen til vores problemer på API-siden, og denne applikation bruger polling - det vil sige, at den konstant beder API'en om nye data. Hvis API'et går ned, tager det vores app med sig, og den øgede belastning fra vores app kan forværre de problemer, vi ser.

Turister i Irland venter måske på en besked

En måde at gå væk fra afstemning er at integrere SignalR, et vedvarende forbindelsesværktøj, der bruger websockets og relaterede teknologier til at tillade servere at skubbe opdateringer til klienter.

Teknologien er skrevet i .NET, og det meste af den dokumentation, du finder rundt på internettet, bruger C #. Denne vejledning dækker en grundlæggende JavaScript-implementering.

Hvad gør den?

Open-source SignalR skaber en vedvarende forbindelse mellem en klient og server. Det bruger websockets først, derefter longpolling og andre teknologier, når websockets ikke er tilgængelige.

Når klienten og serveren har oprettet en forbindelse, kan SignalR bruges til at "udsende" meddelelser til klienten. Når klienten modtager disse beskeder, kan den udføre funktioner som at opdatere en butik.

Det mest almindelige eksempel på websockets er en chat-app - nye data skal vises til brugeren uden at hun behøver at opdatere siden. Men hvis din server får opdateringer om ændring af data, som du har brug for at vise til en klient, er dette muligvis tjenesten for dig.

SignalR på Azure-platformen

Måske fordi det blev udviklet af Microsoft, har SignalR en meget ren integration på Azure cloud-platformen. Ligesom andre funktionsapps opretter du en "in" -trigger og en "out" -binding til udsendelsesmeddelelser.

Omkostninger

Fordi jeg var den første til at se på denne teknologi i stor skala hos mit firma, måtte jeg grave lidt om omkostningerne til denne service. Azure opkræver omkring $ 50 / måned for en "enhed" SignalR-tjeneste - 1000 samtidige forbindelser og en million meddelelser om dagen. Der er også en gratis service for dem, der leger eller små virksomheder.

Det var rigtig godt, jeg gravede ind i disse tal, som du kan se lidt nedenfor.

Opret et SignalR-hub

Lad os komme igang. Vi har brug for et SignalR-hub, to funktionsapps og klientkode for at tilføje til vores webapp.

Gå til SignalR -> Tilføj og udfyld dine oplysninger. Det tager et sekund for medarbejderen at opbygge din service. Sørg for at give tjenesten et anstændigt ressourcenavn, da du bruger det sammen med resten af ​​dine apps. Grib også nøgler -> Forbindelsesstreng til brug i vores binding.

Opsætning af SignalR på Azure

Opret din funktionsapp til afsendelse af SignalR-meddelelser

Fordi vi arbejder med Azure, opretter vi funktionsapps til interface med SignalR. Jeg skrev et start-blog-indlæg om Azure-funktionsapps for lidt siden.

Denne vejledning antager, at du allerede ved, hvordan du arbejder med funktionsapps. Naturligvis kan du arbejde med disse biblioteker uden den bindende magi, men du bliver nødt til at lave din egen oversættelse af .NET-koden!

Forbindelsesappen

Den første ting, vi har brug for, er en måde for klienter at anmode om tilladelse til at oprette forbindelse til vores SignalR-tjeneste. Koden til denne funktion kunne ikke være mere grundlæggende:

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

Magien sker alt sammen i bindingerne, hvor vi trækker vores SignalR-tjeneste ind. Udløseren er en HTTP-anmodning, som vores klient kan ringe til.

{ "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" } ] } 

Klientkoden

For at få adgang til denne metode vil vores klient ringe til:

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

Vores funktionsapp returnerer et urlog accessToken, som vi derefter kan bruge til at oprette forbindelse til vores SignalR-tjeneste. Bemærk, at vi oprettede bindingen med hubNamevores SignalR-tjeneste - det betyder, at du kunne have flere forbindelser til forskellige hubber i en klient.

Broadcasting-tjenesten

Nu er vi klar til at sende meddelelser. Igen starter vi med funktionsappen. Det tager en udløser ind og udsender en SignalR-meddelelse.

En trigger kan være en anden ved hjælp af at sende en besked, en begivenhed fra et event hub eller enhver anden trigger, som Azure understøtter. Jeg er nødt til at udløse databaseændringer.

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

Og koden. Igen, død enkel.

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

SignalR beskeder tage en targetog argumentsobjekt. Når dine udløsere begynder at skyde, er det alt hvad du behøver for at komme i gang med SignalR på serveren! Microsoft har gjort alt dette meget let for os.

Klientkoden

På klientsiden er tingene lidt mere komplekse, men ikke uoverskuelige. Her er resten af ​​klientkoden:

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) 

Vi forbruger connectionUrlog accessTokenvi modtog fra forbindelsesfunktionen tidligere, og opbyg derefter vores forbindelse ved hjælp af disse værdier.

Derefter lytter vi til meddelelser med den delte nøgle (for mig er det statusUpdates) og giver håndterere til lukke og genoprette forbindelsesfunktioner.

Endelig starter vi forbindelsen. Her kan vi tilbyde en indledende belastningsfunktion. Jeg havde brug for en til at hente startdata for at vise den aktuelle status. Hvis du bygger en chat-app, skal du muligvis hente de første beskeder her.

Dette er (næsten måske) alt hvad du behøver for at komme i gang i JavaScript med SignalR på Azure!

Scoping efter bruger

Men måske er du, ligesom mig, nødt til at sende en masse beskeder til mange brugere.

Da jeg først satte dette i produktion på et undersæt af brugere, sprængte jeg enhver forbindelse med hver eneste opdatering. Fordi klientkoden kan omfatte de meddelelser, den lytter til, brugte jeg noget lignende, statusUpdates-${userId}så klienten kun kunne se sine egne opdateringer.

Det kunne fungere fint, hvis du har meget lav lydstyrke, og den mere generelle er fantastisk, hvis alle i dit system har brug for den samme besked. Men den status, jeg arbejder med, er bestemt for et individ.

800.000 SignalR-meddelelser sendt fra Azure-platformen

Husk hvordan Azure opkræver pr. "Enhed", og hver enhed har en million beskeder? Jeg ramte det i løbet af et par timers test af dette i en ikke travl tid.

Azure tæller hver besked, SignalR skal sende som en besked. Det vil sige, hvis fem forbindelser er tilsluttet til din hub, og du sender ti beskeder, tæller det som 50, ikke 10. Dette var en overraskelse for mig og krævede også et par timers forskning.

Vi kan omfatte vores SignalR-funktionskode, så den kun sendes til bestemte brugere. Først opdaterer vi forbindelsesappen, så den accepteres userIdsom en forespørgselsparameter:

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

Derefter opdaterer vi udsendelsesfunktionen, så den kun sendes til den bruger:

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

Broadcasting-tjenesten ved ikke, hvem der har oprettet forbindelse, så du bliver nødt til at udløse den med noget, der har adgang til et unikt id, som klienten også har adgang til.

Klientkoden overføres simpelthen i userId som en forespørgselsparameter:

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

Jeg sværger til dig, det eneste sted på hele internettet, jeg fandt for at fortælle mig, hvordan jeg skulle anmode om en forbindelse ved hjælp af, userIdvar et svar på dette Stack Overflow-spørgsmål.

Internettet er fantastisk, og det er svært at få Azure Azure-dokumenter.

Ressourcer

  • SignalR Javascript-klienten dokumenterer fra Microsoft
  • Konfiguration af brugere og grupper, når der sendes SignalR-meddelelser -

    eksempler i C #, men du kan måske finde ud af, hvordan JavaScript-klienten vil opføre sig og komme med nogle veluddannede gæt.

  • SignalR-servicebindinger til Azure-funktioner
  • Klient API
  • Arbejde med grupper i SignalR
  • Tutorial: Azure SignalR Service-godkendelse med Azure-funktioner

Dette indlæg optrådte oprindeligt på wilkie.tech.