Dziś trochę inny temat. Czy zastanawialiście się kiedyś jak można wbudować w system możliwość wyłączania Azure Functions? Tak, aby nasza aplikacja była w stanie włączyć jakąś funkcję w miarę potrzeb i potem ją wyłączyć. Powodów takich wymagań może być wiele. Możemy przykładowo chcieć odroczyć przetwarzanie jakiś wiadomości do godzin nocnych, tak aby w trakcie dnia nasza funkcja nie obciążała elementu naszej infrastruktury. Innym dość często spotykanym pytaniem w trakcie różnego rodzaju meetupów lub hackatonów jest to czy jesteśmy w stanie w jakiś sposób wyłączyć funkcję automatycznie jeśli wykorzystamy darmową ilość wykonań funkcji.

Nie jest to takie trudne jak nam się wydaje. Generalnie cały problem sprowadza się do zmiany jednego wpisu w pliku functions.json – disabled:

I w sumie jest to nawet całkiem proste. W moim rozwiązaniu stworzyłem oddzielną funkcję, która będzie mogła wyłączać dowolną funkcję na podstawie przesłanych parametrów. Do tego celu wykorzystałem kudu REST API. Funkcja to robiąca jest dość prosta. Powinna ona pobrać plik function.json funkcji, której stan chcemy zmienić. Następnie go zdeserializować i ustawić odpowiednią wartość parametru disabled. I finalnie wgrać jego nową wartość:

#r "Newtonsoft.Json"

using System.Net;
using Newtonsoft.Json;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req)
{
  dynamic data = await req.Content.ReadAsAsync<object>();
  string username = data?.username;
  string password = data?.password;
  string functionSiteRoot = data?.functionSiteRoot;
  string functionName = data?.functionName;
  bool isDisabled = data?.isDisabled;

  WebClient webClient = new WebClient
  {
    Headers = { ["ContentType"] = "application/json" },
    Credentials = new NetworkCredential(username, password),
    BaseAddress = functionSiteRoot
  };

  var functionJson = JsonConvert.DeserializeObject<FunctionSettings>(webClient.DownloadString($"{functionName}/function.json"));
  functionJson.disabled = isDisabled;
  webClient.Headers["If-Match"] = "*";
  webClient.UploadString($"{functionName}/function.json", "PUT", JsonConvert.SerializeObject(functionJson));

  return req.CreateResponse(HttpStatusCode.OK);
}

internal class FunctionSettings
{
  public bool disabled { get; set; }
  public List<Binding> bindings { get; set; }
}

internal class Binding
{
  public string name { get; set; }
  public string type { get; set; }
  public string direction { get; set; }
  public string queueName { get; set; }
  public string connection { get; set; }
  public string accessRights { get; set; }
  public string schedule { get; set; }
}

Tak stworzoną funkcję możemy uruchomić poprzez wysłanie requestu Postman-em:

Mam nadzieję, że parametry są dość czytelne. Większość z nich pobierzemy z PublishSettings aplikacji funkcyjnej w której znajduje się funkcja, którą chcemy wyłączyć:

I na koniec drobna podpowiedź, kopiując kod nie zapomnijcie dodać pliku project.json z następującą zawartością:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Newtonsoft.Json": "9.0.1"
      }
    }
  }
}

W naszej funkcji korzystamy z dodatkowej biblioteki zewnętrznej.