Kako započeti sa SignalR na Azureu s JavaScriptom

Neki dan su se neki fini programeri u mojoj tvrtki pripremali za objavljivanje stranice za ažuriranje statusa. Isprobali smo ga opsežno, ali sad smo se spremali izbaciti ga na veliko.

Bio sam zabrinut zbog njegove ovisnosti o API poslužitelju koji je nedavno djelovao. Nismo utvrdili osnovni uzrok svojih problema na strani API-ja, a ova aplikacija koristi anketiranje - odnosno neprestano traži od API-ja nove podatke. Ako se taj API sruši, povest će našu aplikaciju sa sobom, a povećano opterećenje naše aplikacije može pogoršati probleme koje vidimo.

Turisti u Irskoj, možda čekaju poruku

Jedan od načina da se odmaknete od anketiranja je integriranje SignalR-a, trajnog alata za povezivanje koji koristi web-utičnice i srodne tehnologije kako bi poslužiteljima omogućilo da gurnu ažuriranja klijentima.

Tehnologija je napisana na .NET-u, a većina dokumentacije koju ćete pronaći na webu koristi C #. Ovaj vodič obuhvatit će osnovnu implementaciju JavaScript-a.

Što to radi?

SignalR otvorenog koda stvara trajnu vezu između klijenta i poslužitelja. Prvo koristi web-utičnice, zatim longpolling i druge tehnologije kada web-utičnice nisu dostupne.

Jednom kada su klijent i poslužitelj stvorili vezu, SignalR se može koristiti za "emitiranje" poruka klijentu. Kad klijent primi te poruke, može obavljati funkcije poput ažuriranja trgovine.

Najčešći primjer naveden za websockets je aplikacija za chat - novi podaci moraju se prikazati korisniku, a da ona ne mora osvježavati stranicu. Ali ako vaš poslužitelj dobije bilo kakva ažuriranja o promjeni podataka koje trebate prikazati klijentu, ovo bi mogla biti usluga za vas.

SignalR na Azure platformi

Možda zato što ga je razvio Microsoft, SignalR ima vrlo čistu integraciju na Azure platformi u oblaku. Kao i druge funkcionalne aplikacije, stvorit ćete okidač "in" i "out" za emitiranje poruka.

Troškovi

Budući da sam prvi razmotrio ovu tehnologiju u svojoj tvrtki, morao sam malo istražiti troškove ove usluge. Azure naplaćuje oko 50 USD mjesečno za jednu "jedinicu" usluge SignalR - 1000 istodobnih veza i milijun poruka dnevno. Tu je i besplatna usluga za one koji se igraju ili za male tvrtke.

Bilo je stvarno dobro što sam se ukopao u te brojke, kao što ćete vidjeti malo ispod.

Stvorite čvorište SignalR

Započnimo. Trebat će nam SignalR čvorište, dvije funkcije i klijentski kod za dodavanje u našu web aplikaciju.

Idite na SignalR -> Dodajte i popunite svoje podatke. Potrebna je sekunda da radnik izgradi vašu uslugu. Obavezno dajte usluzi pristojno ime resursa jer ćete ga koristiti s ostalim aplikacijama. Uzmite i tipke -> Niz veze za upotrebu u našem povezivanju.

Postavljanje SignalR-a na Azureu

Izradite svoju funkcijsku aplikaciju za slanje SignalR poruka

Budući da radimo s Azureom, stvorit ćemo funkcionalne aplikacije za sučelje sa SignalR. Prije nekog vremena napisao sam početni post na blogu o aplikacijama s funkcijama Azure.

Ovaj vodič pretpostavlja da već znate kako raditi s funkcijskim aplikacijama. Naravno, s tim bibliotekama možete raditi bez čarobne čarolije, ali morat ćete napraviti vlastiti prijevod .NET koda!

Aplikacija za povezivanje

Prvo što trebamo je način da klijenti zatraže dopuštenje za povezivanje s našom uslugom SignalR. Kôd ove funkcije ne može biti osnovniji:

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

Magija se sve događa u vezama, gdje uvlačimo našu SignalR uslugu. Okidač je HTTP zahtjev koji naš klijent može nazvati.

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

Šifra klijenta

Da bi pristupio ovoj metodi, naš će klijent nazvati:

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

Naša funkcionalna aplikacija vratit će a urli accessToken, koje zatim možemo koristiti za povezivanje s našom uslugom SignalR. Imajte na umu da smo povezivanje stvorili pomoću hubNamenaše usluge SignalR - to znači da biste mogli imati više veza s različitim čvorištima u jednom klijentu.

Usluga emitiranja

Sada smo spremni za početak slanja poruka. Ponovno ćemo početi s aplikacijom funkcije. Uključuje okidač i prikazuje SignalR poruku.

Okidač može biti drugi pomoću objavljivanja poruke, događaja iz čvorišta događaja ili bilo kojeg drugog okidača koji Azure podržava. Moram pokrenuti promjene baze podataka.

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

I kod. Opet, mrtvo jednostavno.

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

SignalR poruke uzimaju targeti argumentsobjekt. Jednom kad se vaši okidači pokrenu, to je sve što vam je potrebno za početak rada SignalR-a na poslužitelju! Microsoft nam je sve ovo vrlo olakšao.

Šifra klijenta

Što se tiče klijenta, stvari su malo složenije, ali ne i upravljive. Evo ostatka klijentskog koda:

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) 

Trošimo connectionUrli accessTokendobili smo od funkcije povezivanja ranije, a zatim gradimo vezu pomoću tih vrijednosti.

Zatim slušamo poruke pomoću zajedničkog ključa (za mene je to statusUpdates) i pružamo rukovatelje za funkcije zatvaranja i ponovnog povezivanja.

Napokon započinjemo vezu. Ovdje možemo pružiti funkciju početnog opterećenja. Trebao sam jedan za dohvaćanje početnih podataka za prikaz trenutnog statusa. Ako gradite aplikaciju za chat, možda ćete ovdje trebati dohvatiti početne poruke.

Ovo je (gotovo, možda) sve što vam je potrebno za početak rada s JavaScriptom sa SignalR na Azureu!

Opseg prema korisniku

Ali možda i vi, poput mene, morate poslati puno poruka velikom broju korisnika.

Kad sam ovo prvi put pustio u proizvodnju, na podskupinu korisnika, uništavao sam svaku vezu sa svakim pojedinačnim ažuriranjem. Budući da klijentski kod može obuhvaćati poruke koje sluša, upotrijebio sam nešto poput statusUpdates-${userId}toga da klijent vidi samo svoja ažuriranja.

To bi moglo dobro funkcionirati ako imate vrlo malo glasnoće, a općenitije je sjajno ako svi u vašem sustavu trebaju istu poruku. Ali status s kojim radim osobit je za pojedinca.

800.000 poruka SignalR poslanih s Azure platforme

Sjećate se kako Azure naplaćuje po "jedinici", a svaka jedinica ima milijun poruka? Pogodila sam to tijekom nekoliko sati testiranja ovoga tijekom ne-zauzetog vremena.

Azure broji svaku poruku koju SignalR mora poslati kao jednu poruku. Odnosno, ako se na vaš čvor poveže pet veza i pošaljete deset poruka, to se računa kao 50, a ne kao 10. To me iznenadilo i zahtijevalo je još nekoliko sati istraživanja.

Naš funkcijski kôd SignalR možemo opsegom poslati samo određenim korisnicima. Prvo ažuriramo aplikaciju za povezivanje kako bi prihvatila userIdkao parametar upita:

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

Zatim ažuriramo funkciju emitiranja tako da šalje samo tom korisniku:

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
  • Vodič: Provjera autentičnosti usluge Azure SignalR s Azure funkcijama

Ovaj se post izvorno pojavio na wilkie.tech.