Container Apps i AKS resolen com executar serveis que estan sempre disponibles. Però bona part del que fa Contoso Airlines no és així. Generar el PDF d'una targeta d'embarcament ocupa dos segons i passa quan un passatger confirma la seva reserva. Sincronitzar el catàleg de tarifes passa quan canvia un document a cosmos-contoso-tarifas-pro. Entre un esdeveniment i el següent no hi ha res a fer, i tanmateix avui Contoso paga per un contenidor encès esperant.

Azure Functions és la resposta: escrius una funció, declares què la dispara, i Azure s'encarrega d'executar-la quan toca i que no existeixi la resta del temps. Aquesta lliçó va més enllà de l'«hola món»: el model de desencadenadors i enllaços, els plans d'allotjament amb les seves contrapartides reals, les dues funcions de producció de Contoso, l'orquestració amb Durable Functions i la lliçó més dura del model, que és la idempotència.

Contingut

  1. Què és la computació sense servidor i què es paga
  2. Desencadenadors i enllaços: el model mental
  3. Plans d'allotjament comparats
  4. Crear el projecte i executar-lo en local
  5. GenerarTarjetaEmbarque: la funció de la cua
  6. SincronizarTarifas: la font de canvis de Cosmos DB
  7. Configuració, identitat administrada i Key Vault
  8. Durable Functions i el flux de facturació en línia
  9. Idempotència, reintents, temps d'espera i límits
  10. Proves, desplegament i supervisió
  11. Quan NO fer servir funcions
  12. Errors Comuns i Consells
  13. Exercicis
  14. Conclusió

  1. Què és la computació sense servidor i què es paga

«Sense servidor» no vol dir que no hi hagi servidors; vol dir que no són cosa teva. No tries mida de màquina, no pedaces, no dimensiones: escrius una unitat de codi i la plataforma l'executa i l'escala.

El que es paga al pla de Consum són tres coses: el nombre d'execucions, el consum en gigabytes-segon (memòria assignada multiplicada pel temps d'execució) i el trànsit sortint. Hi ha una assignació gratuïta mensual generosa, i dues conseqüències pràctiques. La primera: una funció que no s'executa no costa res, i aquí hi ha l'estalvi davant del contenidor encès. La segona, menys intuïtiva: el cost és proporcional al temps d'execució, així que una funció lenta costa més, i una funció que espera bloquejada una crida HTTP externa et cobra per esperar.

  1. Desencadenadors i enllaços: el model mental

Aquí hi ha el concepte que cal interioritzar. Una funció té exactament un desencadenador —el que decideix quan s'executa— i zero o més enllaços d'entrada i de sortida, que són connexions declaratives a altres serveis. La plataforma s'encarrega de la connexió, l'autenticació, la deserialització i els reintents; tu reps objectes i retornes objectes.

Desencadenador Es dispara quan Ús a Contoso
HTTP Arriba una petició API lleugera, webhooks de la passarel·la
Temporitzador Es compleix una expressió cron Purga nocturna de reserves caducades
Blob Es crea o modifica un blob Processar un fitxer carregat
Cua de Storage Apareix un missatge cola-emision-tarjetas
Service Bus Arriba un missatge a cua o subscripció Esdeveniments de reserva confirmada (06-05)
Event Grid Es publica un esdeveniment Blob nou a sttarjetascontosopro
Cosmos DB Canvia un document (font de canvis) Catàleg de tarifes

La diferència que fa valuós el model són els enllaços. Compara:

// SENSE enllacos: lampisteria que cal escriure, provar i mantenir
var credencial = new DefaultAzureCredential();
var cliente = new BlobServiceClient(
    new Uri("https://sttarjetascontosopro.blob.core.windows.net"), credencial);
var contenedor = cliente.GetBlobContainerClient("tarjetas-embarque");
await contenedor.CreateIfNotExistsAsync();
await contenedor.GetBlobClient(nombre).UploadAsync(flujo, overwrite: true);

// AMB enllac de sortida: es declara, i llestos
[BlobOutput("tarjetas-embarque/{nombre}.pdf", Connection = "AlmacenTarjetas")]
public byte[] Pdf { get; set; }

Sis línies de lampisteria substituïdes per una declaració. I no és només brevetat: la connexió, els reintents i l'autenticació amb identitat administrada els gestiona el temps d'execució.

  1. Plans d'allotjament comparats

Consum Flex Consum Premium App Service
Facturació Per execució i GB-s Per execució i GB-s Instàncies sempre actives Pla d'App Service
Arrencada en fred Sí, notable Reduïda; instàncies sempre llestes No No
Escalat màxim 200 instàncies Alt, configurable 100 instàncies Manual o automàtic
Integració amb xarxa virtual No Sí Sí Sí
Durada màxima 5 min (fins a 10) Configurable Il·limitada Il·limitada
Cost sense trànsit Zero Gairebé zero Alt (instància mínima) El del pla

El que tria Contoso i per què:

  • GenerarTarjetaEmbarque va en Flex Consum: necessita xarxa virtual per arribar a pe-storage-tarjetas i pe-sql-reservas per punt privat, cosa que el Consum clàssic no permet, i la seva càrrega és a ràfegues, amb consum gairebé zero de matinada.
  • SincronizarTarifas va també en Flex Consum i a la mateixa aplicació: comparteix xarxa i configuració, i el seu volum és baix.
  • L'orquestració de la facturació en línia amb Durable Functions va en Premium. Les seves orquestracions duren hores —esperen que el passatger pugi un document—, i aquí l'arrencada en fred i el límit de durada importen.
  • Res no va al pla d'App Service, llevat que volguessin reutilitzar plan-contoso-api-pro per aprofitar capacitat ja pagada.

  1. Crear el projecte i executar-lo en local

npm install -g azure-functions-core-tools@4 --unsafe-perm true   # l host, a la teva maquina
func init ContosoFunciones --worker-runtime dotnet-isolated
cd ContosoFunciones
func new --name GenerarTarjetaEmbarque --template "Queue trigger"
func start          # executa les funcions en local, amb depuracio

El model aïllat (dotnet-isolated) és el vigent: la funció corre en el seu propi procés, desacoblada de la versió de l'host. Els valors de configuració locals van a local.settings.json, que no es confirma mai al repositori —és al .gitignore per una raó—; a Azure, aquests mateixos noms es llegeixen de la configuració de l'aplicació.

  1. GenerarTarjetaEmbarque: la funció de la cua

Quan el passatger completa la facturació en línia, app-contoso-reservas-pro encua un missatge a cola-emision-tarjetas de stoperacionescontosopro. Aquesta funció el consumeix, genera el PDF i el deixa al contenidor tarjetas-embarque de sttarjetascontosopro.

public record SolicitudTarjeta(string Localizador, string NumeroVuelo,
                               string Pasajero, string Asiento, DateTime Salida);

public class GenerarTarjetaEmbarque
{
    private readonly ILogger<GenerarTarjetaEmbarque> _reg;
    private readonly IGeneradorPdf _pdf;
    public GenerarTarjetaEmbarque(ILogger<GenerarTarjetaEmbarque> r, IGeneradorPdf p)
        => (_reg, _pdf) = (r, p);

    [Function(nameof(GenerarTarjetaEmbarque))]
    [BlobOutput("tarjetas-embarque/{Localizador}-{Asiento}.pdf", Connection = "AlmacenTarjetas")]
    public async Task<byte[]> Run(
        [QueueTrigger("cola-emision-tarjetas", Connection = "AlmacenOperaciones")]
        SolicitudTarjeta solicitud,
        FunctionContext contexto)
    {
        _reg.LogInformation("Emetent targeta {Loc} vol {Vuelo}",
            solicitud.Localizador, solicitud.NumeroVuelo);

        // Idempotencia: si el blob ja existeix, aquest missatge ja s ha processat (apartat 9)
        if (await _pdf.YaExisteAsync(solicitud.Localizador, solicitud.Asiento))
        {
            _reg.LogInformation("Targeta {Loc} ja emesa; s omet", solicitud.Localizador);
            return null;   // retornar null NO escriu el blob
        }

        return await _pdf.GenerarAsync(solicitud);
    }
}

El que cal entendre d'aquest codi:

  • [QueueTrigger] declara el desencadenador. El temps d'execució sondeja la cua, deserialitza el JSON del missatge directament a SolicitudTarjeta i te'l lliura tipat. Si la deserialització falla, el missatge va a la cua de missatges fallits sense executar el teu codi.
  • Connection = "AlmacenOperaciones" no és una cadena de connexió: és el prefix d'un ajust de configuració. Amb AlmacenOperaciones__queueServiceUri apuntant al compte i la identitat administrada assignada, no hi ha cap clau. Aquest és el punt que més es fa malament.
  • [BlobOutput] amb la plantilla {Localizador}-{Asiento}.pdf: els camps del missatge entrant s'interpolen a la ruta del blob. El nom del fitxer és determinista, i d'aquí surt de franc la comprovació d'idempotència.
  • Retornar null no escriu el blob, la manera neta de tallar sense llançar una excepció. I la injecció de dependències funciona com en qualsevol aplicació .NET: el constructor rep el registrador i el generador de PDF, cosa que fa la funció provable amb proves unitàries.

  1. SincronizarTarifas: la font de canvis de Cosmos DB

Quan l'equip comercial actualitza una tarifa al contenidor tarifas de cosmos-contoso-tarifas-pro, la font de canvis que ja coneixes de 03-03 lliura el document modificat a aquesta funció, que refresca l'índex de cerca i avisa la memòria cau del motor de disponibilitat.

public class SincronizarTarifas
{
    private readonly ILogger<SincronizarTarifas> _reg;
    private readonly IIndiceTarifas _indice;
    public SincronizarTarifas(ILogger<SincronizarTarifas> r, IIndiceTarifas i)
        => (_reg, _indice) = (r, i);

    [Function(nameof(SincronizarTarifas))]
    public async Task Run(
        [CosmosDBTrigger(
            databaseName: "catalogo",
            containerName: "tarifas",
            Connection = "CosmosTarifas",
            LeaseContainerName = "arrendamientos",
            CreateLeaseContainerIfNotExists = true)]
        IReadOnlyList<Tarifa> cambios)
    {
        foreach (var tarifa in cambios)
        {
            // Upsert per clau: processar dues vegades deixa el mateix resultat
            await _indice.UpsertAsync(tarifa);
            _reg.LogInformation("Tarifa {Id} de {Ruta} sincronitzada",
                tarifa.Id, tarifa.OrigenDestino);
        }
    }
}

El contenidor d'arrendaments mereix atenció: és on el desencadenador desa fins on ha llegit cada partició. Viu a la mateixa base de dades, consumeix les seves pròpies RU/s i, si l'esborres, la funció reprocessa des del principi. La funció rep lots de canvis, no documents solts, i la clau de partició /origenDestino determina el paral·lelisme: cada partició es processa en ordre i de manera independent.

  1. Configuració, identitat administrada i Key Vault

# L aplicacio de funcions, en Flex Consum i integrada a la xarxa virtual
az functionapp create \
  --resource-group rg-contoso-reservas-pro --name func-contoso-tarjetas-pro \
  --storage-account stoperacionescontosopro --flexconsumption-location westeurope \
  --runtime dotnet-isolated --runtime-version 8.0 --vnet vnet-contoso-pro --subnet snet-integracion-app \
  --tags entorno=produccion proyecto=contoso-reservas \
         centro-coste=CC-1042 [email protected]

# Identitat administrada assignada per l usuari, la de sempre
az functionapp identity assign -g rg-contoso-reservas-pro -n func-contoso-tarjetas-pro \
  --identities $(az identity show -g rg-contoso-seguridad-pro \
      -n id-contoso-api-pro --query id -o tsv)

# Connexions PER IDENTITAT: nom de servei, no clau
az functionapp config appsettings set -g rg-contoso-reservas-pro \
  -n func-contoso-tarjetas-pro --settings \
  "AlmacenOperaciones__queueServiceUri=https://stoperacionescontosopro.queue.core.windows.net" \
  "AlmacenTarjetas__blobServiceUri=https://sttarjetascontosopro.blob.core.windows.net" \
  "[email protected](SecretUri=https://kv-contoso-pro.vault.azure.net/secrets/clave-pasarela/)"

Tres idees: les connexions amb el sufix __queueServiceUri / __blobServiceUri activen el mode per identitat, sense claus; la referència a Key Vault amb la sintaxi @Microsoft.KeyVault(...) de 04-03 resol el secret en temps d'execució i el valor no es veu mai al portal; i la identitat necessita els seus rols —Col·laborador de dades de la cua de Storage, Col·laborador de dades de Blob Storage i Usuari de secrets de Key Vault—.

  1. Durable Functions i el flux de facturació en línia

Les funcions normals són sense estat i de curta durada. I si el procés té diversos passos, triga hores i cal saber per on anava? Durable Functions hi afegeix estat durador i represa: un orquestrador descriu el flux amb codi normal, i la seva execució es persisteix automàticament a cada punt d'espera.

sequenceDiagram
  participant P as Passatger
  participant O as OrquestadorCheckIn
  participant A as Activitats
  P->>O: Inicia facturacio (localitzador)
  O->>A: ValidarReserva
  A-->>O: Reserva valida
  par Fan-out
    O->>A: ComprovarDocumentacio
    O->>A: AssignarSeient
    O->>A: CalcularEquipatge
  end
  A-->>O: Fan-in: resultats
  O->>P: Demana foto del passaport
  Note over O: Espera esdeveniment extern (fins a 24 h)
  P-->>O: DocumentSubit
  O->>A: EmetreTargeta -> cola-emision-tarjetas

Els tres patrons, aplicats:

  • Encadenament de funcions: ValidarReserva → EmitirTarjeta. Cada pas fa servir la sortida de l'anterior; si el procés cau al tercer pas, en reprendre no repeteix els dos primers.
  • Fan-out / fan-in: documentació, seient i equipatge són independents; es llancen en paral·lel i s'esperen totes. Redueix el temps total al del pas més lent.
  • Esperar un esdeveniment extern: l'orquestrador s'atura a WaitForExternalEvent("DocumentoSubido") amb un temps d'espera de 24 hores. Mentre espera no consumeix còmput ni factura; és el que fa inviable resoldre això amb una funció normal, limitada a minuts.
[Function(nameof(OrquestadorCheckIn))]
public static async Task<ResultadoCheckIn> Run(
    [OrchestrationTrigger] TaskOrchestrationContext contexto)
{
    var loc = contexto.GetInput<string>();
    var reserva = await contexto.CallActivityAsync<Reserva>("ValidarReserva", loc);

    // Fan-out: tres activitats en paral.lel
    await Task.WhenAll(                              // ...i fan-in en esperar-les
        contexto.CallActivityAsync<object>("ComprobarDocumentacion", reserva),
        contexto.CallActivityAsync<object>("AsignarAsiento", reserva),
        contexto.CallActivityAsync<object>("CalcularEquipaje", reserva));

    // Espera humana: no consumeix computo mentrestant
    using var cts = new CancellationTokenSource();
    var evento = contexto.WaitForExternalEvent<string>("DocumentoSubido");
    var plazo  = contexto.CreateTimer(contexto.CurrentUtcDateTime.AddHours(24), cts.Token);
    if (evento == await Task.WhenAny(evento, plazo)) cts.Cancel();
    else return new ResultadoCheckIn(loc, "Caducado");

    await contexto.CallActivityAsync("EmitirTarjeta", reserva);
    return new ResultadoCheckIn(loc, "Completado");
}

Regla d'or de l'orquestrador: el seu codi ha de ser determinista. Res de DateTime.Now, Guid.NewGuid() ni crides d'E/S directes, perquè l'orquestrador es reexecuta des del principi cada vegada que reprèn, reproduint el seu historial. Fes servir contexto.CurrentUtcDateTime i delega tot el que no és determinista en activitats.

  1. Idempotència, reintents, temps d'espera i límits

Aquesta és la lliçó que gairebé ningú no explica al principi i que tothom aprèn en producció: les cues garanteixen el lliurament almenys una vegada, no exactament una vegada. Si la funció cau després de generar el PDF però abans de confirmar el missatge, el missatge reapareix i la funció s'executa una altra vegada amb les mateixes dades. Sense protecció, el passatger rep dues targetes i el registre comptable queda desquadrat.

Com es protegeix, en ordre de preferència:

Estratègia Com Aplicació a Contoso
Operació naturalment idempotent Escriure amb clau determinista, upsert en lloc d'insert SincronizarTarifas: l'upsert per identificador
Comprovació prèvia Veure si el resultat ja existeix abans de treballar GenerarTarjetaEmbarque: el blob {Localizador}-{Asiento}.pdf
Registre de processats Taula amb l'identificador del missatge registroembarques de stoperacionescontosopro

Sobre els reintents: la cua reintenta automàticament (cinc vegades per defecte) i després envia el missatge a la cua de missatges fallits. Un missatge que falla sempre —un JSON mal format, un vol inexistent— s'anomena missatge enverinat, i sense cua de missatges fallits bloquejaria la cua indefinidament. Vigila aquesta cua amb una alerta: si creix, alguna cosa està trencada.

Sobre temps d'espera i límits: 5 minuts per defecte a Consum (ampliable a 10), configurable a Flex i sense límit a Premium, amb el valor a functionTimeout de host.json. Un missatge de cua gran no hi cap (64 KB), així que envia referències, no càrregues: l'identificador del blob, no el PDF. I maxConcurrentCalls limita el paral·lelisme, que cal abaixar quan la funció escriu a db-reservas, perquè mil instàncies obrint connexions esgoten el grup de la base de dades.

  1. Proves, desplegament i supervisió

La lògica va en classes injectades —IGeneradorPdf, IIndiceTarifas—, així que es prova amb proves unitàries normals; la funció es limita a orquestrar. Per a la integració, func start amb l'emulador de Storage. El desplegament reutilitza la canalització de 05-04, amb ranures: es desplega a preproduccion, s'escalfa i s'intercanvia.

- task: AzureFunctionApp@2
  inputs:
    azureSubscription: sc-contoso-pro
    appType: functionApp
    appName: func-contoso-tarjetas-pro
    deployToSlotOrASE: true
    slotName: preproduccion
    package: $(Pipeline.Workspace)/artefacto/funciones.zip
- task: AzureAppServiceManage@0                    # i despres l intercanvi
  inputs:
    azureSubscription: sc-contoso-pro
    Action: 'Swap Slots'
    WebAppName: func-contoso-tarjetas-pro
    SourceSlot: preproduccion

Application Insights ve integrat i és on es veu tot: execucions amb èxit i amb error, durada, telemetria de dependències i la traça d'extrem a extrem des de la cua fins al blob. La seva explotació és 07-03; aquí n'hi ha prou de saber que s'habilita en crear l'aplicació i que sense ell una funció que falla és una caixa negra.

  1. Quan NO fer servir funcions

  • Processos de llarga durada amb estat en memòria: fes servir Durable Functions o un contenidor. I càrregues constants i altes: si el codi s'executa sense parar, un pla fix o Container Apps surt més barat que pagar per execució.
  • Latència mínima garantida a la primera petició: l'arrencada en fred del pla de Consum no és acceptable per a la ruta de compra.
  • Aplicacions amb molta lògica compartida i desplegament conjunt: si les «funcions» són un monòlit trossejat que sempre es desplega junt, és una API, i el seu lloc és App Service o Container Apps. El mateix amb connexions persistents o dependències pesades d'arrencada: cada instància nova paga aquesta arrencada, i amb escalat agressiu la destinació pateix.

Errors Comuns i Consells

  • No fer la funció idempotent. Es manifesta com a duplicats esporàdics impossibles de reproduir. Dissenya-ho des del primer dia.
  • Fer servir cadenes de connexió amb clau als ajustos de Connection. Fes servir el sufix __blobServiceUri amb identitat administrada.
  • Ficar la càrrega completa al missatge. Límit de 64 KB a cues de Storage: envia la referència.
  • Escriure codi no determinista en un orquestrador. DateTime.Now o Guid.NewGuid() produeixen resultats incoherents en reprendre.
  • Ignorar la cua de missatges fallits, on acaben els missatges enverinats; si ningú no la mira, els errors són invisibles. I no limitar la concurrència quan la funció escriu a db-reservas: mil instàncies esgoten el grup de connexions.
  • Confirmar local.settings.json. Conté credencials locals. Comprova-ho a la revisió de 05-02.
  • Consell: mesura la durada a Application Insights; abaixar una funció de 4 s a 1,5 s redueix la factura de Consum gairebé en la mateixa proporció. I una funció, una responsabilitat: si té tres desencadenadors lògics diferents, són tres funcions.

Exercicis

Exercici 1. Contoso Millas necessita una funció que, quan un passatger completa un vol, sumi les milles corresponents al seu perfil a cosmos-contoso-tarifas-pro. Els esdeveniments arriben per cola-vuelos-completados.

  1. Tria desencadenador, enllaços i pla d'allotjament, i justifica-ho.
  2. El primer dia en producció, alguns passatgers apareixen amb les milles duplicades. Explica'n la causa exacta, dona dues maneres d'arreglar-ho, i indica les etiquetes del recurs i l'alerta que configuraries des del dia u.

Exercici 2. Dissenya amb Durable Functions el procés de reemborsament d'un bitllet: validar la sol·licitud, comprovar en paral·lel penalització i saldo de la passarel·la, esperar l'aprovació d'un supervisor (màxim 72 hores) i, si s'aprova, executar l'abonament i notificar.

  1. Indica quin patró cobreix cada tram i per què no es pot resoldre amb una funció normal al pla de Consum.
  2. Escriu en pseudocodi l'espera del supervisor amb la seva caducitat i digues què passa si l'orquestrador es reinicia mentre espera.

Exercici 3. Una funció amb desencadenador HTTP consulta db-reservas i respon en 200 ms quan hi ha poc trànsit, però en obrir la venda de places retorna errors de temps d'espera de la base de dades.

  1. Explica el mecanisme de la fallada.
  2. Proposa tres mesures correctores.

Solucions

Solució 1:

  1. Desencadenador de cua de Storage sobre cola-vuelos-completados, amb enllaç de sortida a Cosmos DB al contenidor perfiles. Pla Flex Consum: volum a ràfegues concentrades en aterrar els vols, cost gairebé zero de matinada, i necessita xarxa virtual per arribar al punt privat de Cosmos.
  2. La causa és el lliurament almenys una vegada: si la funció suma les milles i cau abans de confirmar el missatge, aquest reapareix i es torna a sumar. Sumar és l'operació no idempotent per excel·lència. Arranjament (a): desar al document del perfil el conjunt d'identificadors de vol ja acreditats i descartar l'esdeveniment si ja hi és —comprovació prèvia dins de la mateixa escriptura—. Arranjament (b): registrar l'identificador del missatge a la taula registroembarques abans de sumar, i descartar si ja existeix. La (a) és preferible perquè no hi afegeix un altre magatzem ni una altra finestra de fallada. Etiquetes: entorno, proyecto=contoso-millas, centro-coste=CC-2077 i propietario. L'alerta del primer dia és sobre la longitud de la cua de missatges fallits: tan bon punt creix, hi ha missatges enverinats i passatgers sense les seves milles.

Solució 2:

  1. Validar → comprovar → abonar → notificar és encadenament; penalització i saldo en paral·lel són fan-out / fan-in; l'aprovació del supervisor és esperar un esdeveniment extern. No cap en una funció normal perquè l'espera dura fins a 72 hores i el pla de Consum talla als 5 o 10 minuts; a més caldria persistir el punt exacte del procés, i una funció normal és sense estat.
  2. var evento = contexto.WaitForExternalEvent<Decision>("AprobacionSupervisor"); juntament amb var plazo = contexto.CreateTimer(contexto.CurrentUtcDateTime.AddHours(72), cts.Token); i un Task.WhenAny sobre tots dos; si guanya el termini es rebutja per caducitat, i si guanya l'esdeveniment es cancel·la el temporitzador. Si l'orquestrador es reinicia mentre espera, no passa res: la instància no està ocupant còmput, el seu historial està persistit i en reprendre es reprodueix fins al punt d'espera. Aquesta és exactament la propietat que aporta el model durador.

Solució 3:

  1. La funció escala a desenes o centenars d'instàncies en paral·lel, i cada instància obre les seves pròpies connexions a db-reservas. El grup de connexions del servidor s'esgota, les peticions s'encuen i acaben expirant. El símptoma apareix a la base de dades, però la causa és l'escalat descontrolat de la funció.
  2. (a) Limitar la concurrència a host.json i fixar functionAppScaleLimit a un sostre compatible amb la base de dades. (b) Reutilitzar el client de base de dades com a estàtic o singleton en lloc de crear-ne un per invocació, perquè les connexions s'agrupin. (c) Treure la sincronia del camí: encuar la petició i respondre immediatament, o posar una memòria cau al davant per a les consultes repetides. Com a reforç, revisar el nivell de sql-contoso-reservas-pro (03-02), tot i que escalar la base de dades sense arreglar la concurrència només mou el límit.

Conclusió

Ja saps què vol dir de debò «sense servidor»: no hi ha màquina a triar ni a pedaçar, es paga per execucions i gigabytes-segon, una funció aturada costa zero i una funció lenta costa més. Tens interioritzat el model mental de desencadenadors i enllaços —un desencadenador que decideix quan, enllaços d'entrada i sortida que eliminen la lampisteria de connectar-se, autenticar-se i reintentar— i coneixes els més usats amb el seu encaix a Contoso. Saps comparar els plans d'allotjament per arrencada en fred, escalat, xarxa virtual, durada i cost, i per què les funcions de Contoso van en Flex Consum mentre l'orquestració de la facturació en línia necessita Premium.

Has escrit les dues funcions reals: GenerarTarjetaEmbarque, disparada per cola-emision-tarjetas, amb enllaç de sortida al contenidor tarjetas-embarque mitjançant una plantilla de nom determinista que regala la idempotència; i SincronizarTarifas, alimentada per la font de canvis de cosmos-contoso-tarifas-pro amb el seu contenidor d'arrendaments i el seu processament per lots. Les has configurat amb connexions per identitat (__blobServiceUri, __queueServiceUri) i referències a kv-contoso-pro, sense ni una sola clau. Amb Durable Functions has orquestrat la facturació en línia aplicant encadenament, fan-out/fan-in i espera d'esdeveniment extern durant 24 hores sense consumir còmput, respectant la regla de l'orquestrador determinista. I t'endus la lliçó dura: almenys una vegada, no exactament una vegada, amb les seves tres estratègies d'idempotència, la cua de missatges fallits que cal vigilar, els temps d'espera, el límit de 64 KB i la concurrència que cal frenar quan al darrere hi ha una base de dades. Saps desplegar amb ranures des de la canalització, supervisar amb Application Insights (07-03) i, sobretot, quan no fer servir funcions.

Queda una peça incòmoda. Quan un vol es retarda, Contoso ha de buscar els passatgers afectats a db-reservas, avisar-los per correu i per missatge, publicar al canal de l'equip d'operacions i obrir una incidència al sistema de suport. Res d'això no és lògica de negoci complexa: és enganxar sistemes entre si, i escriure-ho com a codi significa mantenir a mà quatre integracions amb les seves autenticacions, els seus reintents i els seus formats. A més, qui coneix aquest procés no és en Diego, és l'equip d'operacions, que no programa. La lliçó següent, Azure Logic Apps, és exactament per a això: fluxos de treball visuals sobre un catàleg de més de mil connectors, amb la seva definició en JSON versionable, el seu control de flux, la seva gestió d'errors i el seu historial d'execucions, i amb el criteri per saber quan toca una aplicació lògica, quan una funció i quan Data Factory.

Curs d'Azure

Mòdul 1: Introducció a Azure

Mòdul 2: Serveis principals d'Azure

Mòdul 3: Bases de dades d'Azure

Mòdul 4: Seguretat a Azure

Mòdul 5: Azure DevOps

Mòdul 6: Serveis avançats d'Azure

Mòdul 7: Monitoratge i gestió

Mòdul 8: Gestió i optimització de costos

Mòdul 9: Estudis de cas i millors pràctiques

© Copyright 2026. Tots els drets reservats