Azure Functions 3 – Timer Trigger

28. 11. 2022 Azure, Programming

Timer Trigger je funkce, která se vykoná jednou za daný čas. Pokud například potřebujete každý den v 8:00 zaslat e-maily, tak tato funkce je jednoduchou a levnou možností, jak toho dosáhnout. To a mnoho dalšího si v tomto článku ukážeme.

Základ projektu

Pokud by se vám něco v následujících krocích nepovedlo zprovoznit, tak se na celý projekt můžete kouknout na GitHub.

Předtím, než začneme, bych doporučil přečíst si předešlé články, jelikož je zde pár kroků, které už jsem vysvětloval, proto je tedy přeskočím. Musíme mít také splněné následující věci:

Abychom projekt založili, tak musíme zadat příkaz func init, zde vyberte node a poté vyberte javascript. Jakmile máme založený projekt, tak do něj musíme přidat funkci, která se bude v daný čas opakovat. Zadejte tedy prosím příkaz func new ve stejném adresáři jako jste zadaly func init. Kdyby to chvíli trvalo, tak se nebojte. U nových projektů je to normální.

Jakmile vám najede menu s výběrem, tak se v dolní části nachází Timer Trigger, ten vyberte. Dále musíte spustit příkaz func settings add AzureWebJobsStorage UseDevelopmentStorage=true. Toto nastavení musíme udělat, protože Timer Trigger vyžaduje Azure Storage připojení, které mu musíte před publikováním zadat stejným způsobem, akorát místo UseDevelopmentStorage=true zadáte váš connection string.

V tuto chvíli musíte ještě udělat poslední věc, což je zapnutí samotného emulátoru. To uděláte tak, že změníte adresář do C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator. Zde poté zadáte 2 příkazy. Jeden na založení Azure Storage instance a druhý na zapnutí založené instance. První příkaz vypadá takto: ./AzureStorageEmulator.exe init. Druhý potom takto: ./AzureStorageEmulator.exe start.

Pokud se vám vše povedlo, jak mělo, tak byste měli mít následující strukturu projektu:

Struktura projektu, Timer Trigger
Struktura projektu | Zdroj: autor

Jak si můžete všimnout, tak složka s názvem vaší funkce obsahuje readme.md. Doporučuji tento soubor přečíst, i přes to, že se k věcem, co jsou v něm napsané, dostaneme. Prozatím se budeme zajímat pouze o dva soubory.

První je function.json:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}

Druhý je index.js:

module.exports = async function (context, myTimer) {
    var timeStamp = new Date().toISOString();
    
    if (myTimer.IsPastDue)
    {
        context.log('JavaScript is running late!');
    }
    context.log('JavaScript timer trigger function ran!', timeStamp);   
};

Vytváření funkcionality

Než se pustíme do vývoje, tak si musíme ujasnit, co je náš cíl. Cíl pro tento článek je: vytvořit kus kódu, který se spustí každý den v 8:00 a zašle email s pozdravem.

Kód na zaslání emailů

I přesto, že zde nebudeme nastavovat dobu, tak se rychle musíme podívat do function.json, abychom zde nastavili opakování na každých 5 sekund. Zatím to uděláme tím, že náš soubor následně změníme:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "*/5 * * * * *"
    }
  ]
}

Teď zkusíme, že se nám funkce spustí každých 5 sekund tím, že vypíšeme něco do konzole. Tudíž musíme upravit index.js:

module.exports = async function (context, myTimer) {
  console.log("Funkce se uspesne spustila");
};

Poté zadáme příkaz func start a měly bychom vidět následující output:

Výpis po zpuštění a čekání 15 sekund | Zdroj: vlastní
Výpis po zpuštění a čekání 15 sekund | Zdroj: autor

Super, to bylo úvodní nastavení, a teď můžeme jít na zasílání e-mailů. Vzhledem k tomu, že si chceme zasílání zjednodušit, tak si doinstalujeme knihovnu Nodemailer. To uděláme následujícím příkazem:

npm install nodemailer

Další věc, kterou musíme udělat, je připojení se k SMTP serveru s našimi údaji. V našem případě využijeme Nodemailerem poskytovaného SMTP serveru s možností generace nového dočasného účtu:

const nodemailer = require("nodemailer");

module.exports = async function (context, myTimer) {
  // Vytvořte dočasný účet.
  let testAcc = await nodemailer.createTestAccount();

  // Vytvořte znovupoužitelný transporter
  let transporter = nodemailer.createTransport({
    host: "smtp.ethereal.email",
    port: 587,
    secure: false, // true pro 465, false pro všechny ostatní porty
    auth: {
      user: testAcc.user, // generované ethereal username
      pass: testAcc.pass, // generované ethereal heslo
    },
  });
};

Dále pak musíme samotný e-mail odeslat. To uděláme následovně:

const nodemailer = require("nodemailer");

module.exports = async function (context, myTimer) {
  // Vytvořte dočasný účet.
  let testAcc = await nodemailer.createTestAccount();

  // Vytvořte znovupoužitelný transporter
  let transporter = nodemailer.createTransport({
    host: "smtp.ethereal.email",
    port: 587,
    secure: false, // true pro 465, false pro všechny ostatní porty
    auth: {
      user: testAcc.user, // generované ethereal username
      pass: testAcc.pass, // generované ethereal heslo
    },
  });

  // Zaslání mailu
  let messageInfo = await transporter.sendMail({
    from: '"Examle" <[email protected]>', // Zobrazovaná emailová adresa odesílatele
    to: "[email protected], [email protected]", // Seznam příjemců
    subject: "Example email", // Subject
    text: "Hello world?", // Kontent emailu
  });

  // Preview emailu je možné pouze s ethereal.email
  console.log("Preview URL: %s", nodemailer.getTestMessageUrl(messageInfo));
};

Nastavení opakované doby

Jelikož už máme nastavené zasílání e-mailů, tak se můžeme vrhnout na nastavení času. To se řídí dle standardizovaných cron expresí. V jednoduchosti je základní patern: ‚{sekundy} {minuty} {hodiny} {dny} {měsíce} {dny v týdnu}‚. Na každém místě v tomto paternu stojí * (hvězdička). Tuto hvězdičku si můžeme přeložit jako „Každých„. Chceme ale nastavit Každých 1 dní. K tomu nám slouží / (lomeno). Znak lomeno a za ním následující číslo indikuje „každých“, kolik jednotek se má akce opakovat. Pokud však chceme, aby se akce opakovala každou minutu na páté sekundě, tak zadáme pouze číslo bez lomítka. Tudíž každých 5 sekund by vypadalo následovně: ‚*/5 * * * * *‚, ale každou pátou sekundu v minutě takto: ‚5 * * * * * ‚.

Jakmile toto víme, tak si musíme uvědomit, čeho chceme dosáhnout. Vzhledem k zadání cíle, chceme zaslat emaily každý den ráno v 8 hodin. Tudíž musí naše exprese vypadat takto: ‚* * 8 * * *‚. Tuto expresi poté zadáme do našeho function.json souboru a můžeme publikovat na Azure:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "* * 8 * * *"
    }
  ]
}

V repositáři na GitHub však nechám cron na každých 5 sekund, pro jednoduché debugování.

Závěr

Timer Trigger je, dle mého názoru, jeden z nejvíce užitečných funkcí v Azure Functions a osobně ho dlouhodobě bez problémů využívám. Je to super věc na automatizaci malých úkolů, emailů. Další skvělá věc je to, že je to v podstatě zdarma, nebo se musíte opravdu snažit, abyste vypotřebovali zdarma limitů.

Doufám, že se vám série líbila, pokud byste měli jakékoliv otázky nebo problémy, můžete se obrátit na github repo diskuzi, kde vám do maximálně dvou dnů odpovím na jakékoliv otázky.