Diagnostyka w usłudze Durable Functions na platformie Azure

Istnieje kilka opcji diagnozowania problemów z rozszerzeniem Durable Functions. Niektóre opcje są takie same jak w przypadku funkcji regularnych, a niektóre z nich są unikatowe dla usługi Durable Functions.

Szczegółowe dane dotyczące aplikacji

Szczegółowe informacje aplikacji to zalecany sposób wykonywania diagnostyki i monitorowania w usłudze Azure Functions. To samo dotyczy rozszerzenia Durable Functions. Aby zapoznać się z omówieniem sposobu wykorzystania Szczegółowe informacje aplikacji funkcji, zobacz Monitorowanie usługi Azure Functions.

Rozszerzenie Durable Extension usługi Azure Functions emituje również zdarzenia śledzenia, które umożliwiają śledzenie kompleksowego wykonywania orkiestracji. Te zdarzenia śledzenia można znaleźć i wykonywać zapytania za pomocą narzędzia Application Szczegółowe informacje Analytics w witrynie Azure Portal.

Dane śledzenia

Każde zdarzenie cyklu życia wystąpienia orkiestracji powoduje zapisanie zdarzenia śledzenia w kolekcji śladów w usłudze Application Szczegółowe informacje. To zdarzenie zawiera ładunek customDimensions z kilkoma polami. Nazwy pól są poprzedzane ciągiem prop__.

  • hubName: nazwa centrum zadań, w którym są uruchomione aranżacje.
  • appName: nazwa aplikacji funkcji. To pole jest przydatne, gdy masz wiele aplikacji funkcji współużytkowania tego samego wystąpienia aplikacji Szczegółowe informacje.
  • slotName: miejsce wdrożenia, w którym jest uruchomiona bieżąca aplikacja funkcji. To pole jest przydatne w przypadku używania miejsc wdrożenia do obsługi wersji aranżacji.
  • functionName: nazwa funkcji orkiestratora lub działania.
  • functionType: typ funkcji, taki jak Orchestrator lub Activity.
  • instanceId: unikatowy identyfikator wystąpienia aranżacji.
  • state: stan wykonywania cyklu życia wystąpienia. Prawidłowe wartości to:
    • Zaplanowane: funkcja została zaplanowana na wykonanie, ale nie została jeszcze uruchomiona.
    • Rozpoczęto: funkcja została uruchomiona, ale nie została jeszcze wyczekiwana ani ukończona.
    • Awaited: Orkiestrator zaplanował pewną pracę i czeka na jego ukończenie.
    • Nasłuchiwanie: orkiestrator nasłuchuje powiadomienia o zdarzeniach zewnętrznych.
    • Ukończono: funkcja została pomyślnie ukończona.
    • Niepowodzenie: funkcja nie powiodła się z powodu błędu.
  • przyczyna: Dodatkowe dane skojarzone ze zdarzeniem śledzenia. Jeśli na przykład wystąpienie oczekuje na powiadomienie o zdarzeniu zewnętrznym, to pole wskazuje nazwę zdarzenia, na które czeka. Jeśli funkcja nie powiodła się, to pole będzie zawierać szczegóły błędu.
  • isReplay: wartość logiczna wskazująca, czy zdarzenie śledzenia jest przeznaczone do ponownego wykonania.
  • extensionVersion: wersja rozszerzenia Durable Task. Informacje o wersji są szczególnie ważne podczas raportowania możliwych usterek w rozszerzeniu. Długotrwałe wystąpienia mogą zgłaszać wiele wersji w przypadku wystąpienia aktualizacji podczas jej działania.
  • sequenceNumber: numer sekwencji wykonywania zdarzenia. W połączeniu ze znacznikiem czasu pomaga uporządkować zdarzenia według czasu wykonania. Należy pamiętać, że ta liczba zostanie zresetowana do zera, jeśli host zostanie uruchomiony ponownie podczas działania wystąpienia, dlatego ważne jest, aby zawsze sortować według znacznika czasu, a następnie sequenceNumber.

Szczegółowość danych śledzenia emitowanych do aplikacji Szczegółowe informacje można skonfigurować w logger sekcji host.json (Functions 1.x) lub logging (Functions 2.0) pliku.

Functions 1.0

{
    "logger": {
        "categoryFilter": {
            "categoryLevels": {
                "Host.Triggers.DurableTask": "Information"
            }
        }
    }
}

Functions 2.0

{
    "logging": {
        "logLevel": {
            "Host.Triggers.DurableTask": "Information",
        },
    }
}

Domyślnie wszystkie zdarzenia śledzenia niepotwarzania są emitowane. Ilość danych można zmniejszyć, ustawiając wartość Host.Triggers.DurableTask na "Warning" lub "Error" w takim przypadku zdarzenia śledzenia będą emitowane tylko w wyjątkowych sytuacjach. Aby włączyć emitowanie pełnych zdarzeń odtwarzania orkiestracji, ustaw logReplayEvents wartość na true w pliku konfiguracji host.json .

Uwaga

Domyślnie dane telemetryczne usługi Application Szczegółowe informacje są próbkowane przez środowisko uruchomieniowe usługi Azure Functions, aby uniknąć zbyt częstego emitowania danych. Może to spowodować utratę informacji śledzenia w przypadku wystąpienia wielu zdarzeń cyklu życia w krótkim czasie. W artykule Monitorowanie usługi Azure Functions wyjaśniono, jak skonfigurować to zachowanie.

Dane wejściowe i wyjściowe funkcji orkiestratora, działania i jednostki nie są domyślnie rejestrowane. To domyślne zachowanie jest zalecane, ponieważ rejestrowanie danych wejściowych i wyjściowych może zwiększyć koszty Szczegółowe informacje aplikacji. Ładunki wejściowe i wyjściowe funkcji mogą również zawierać poufne informacje. Zamiast tego liczba bajtów dla danych wejściowych i wyjściowych funkcji jest rejestrowana zamiast rzeczywistych ładunków domyślnie. Jeśli chcesz, aby rozszerzenie Durable Functions rejestrowało pełne ładunki wejściowe i wyjściowe, ustaw traceInputsAndOutputs właściwość na true w pliku konfiguracji host.json .

Zapytanie o pojedyncze wystąpienie

Poniższe zapytanie przedstawia historyczne dane śledzenia dla pojedynczego wystąpienia orkiestracji funkcji Hello Sequence . Jest on napisany przy użyciu język zapytań Kusto. Filtruje wykonywanie odtwarzania w taki sposób, aby była wyświetlana tylko logiczna ścieżka wykonywania. Zdarzenia można porządkować według i timestampsequenceNumber , jak pokazano w poniższym zapytaniu:

let targetInstanceId = "ddd1aaa685034059b545eb004b15d4eb";
let start = datetime(2018-03-25T09:20:00);
traces
| where timestamp > start and timestamp < start + 30m
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = customDimensions["prop__functionName"]
| extend instanceId = customDimensions["prop__instanceId"]
| extend state = customDimensions["prop__state"]
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend sequenceNumber = tolong(customDimensions["prop__sequenceNumber"])
| where isReplay != true
| where instanceId == targetInstanceId
| sort by timestamp asc, sequenceNumber asc
| project timestamp, functionName, state, instanceId, sequenceNumber, appName = cloud_RoleName

Wynikiem jest lista zdarzeń śledzenia, które pokazują ścieżkę wykonywania aranżacji, w tym wszystkie funkcje działania uporządkowane według czasu wykonywania w kolejności rosnącej.

Zapytanie uporządkowane Szczegółowe informacje aplikacji w jednym wystąpieniu

Zapytanie podsumowania wystąpienia

Poniższe zapytanie wyświetla stan wszystkich wystąpień aranżacji, które zostały uruchomione w określonym zakresie czasu.

let start = datetime(2017-09-30T04:30:00);
traces
| where timestamp > start and timestamp < start + 1h
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = tostring(customDimensions["prop__functionName"])
| extend instanceId = tostring(customDimensions["prop__instanceId"])
| extend state = tostring(customDimensions["prop__state"])
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend output = tostring(customDimensions["prop__output"])
| where isReplay != true
| summarize arg_max(timestamp, *) by instanceId
| project timestamp, instanceId, functionName, state, output, appName = cloud_RoleName
| order by timestamp asc

Wynikiem jest lista identyfikatorów wystąpień i ich bieżący stan środowiska uruchomieniowego.

Zapytanie aplikacji Szczegółowe informacje pojedynczego wystąpienia

Trwałe rejestrowanie struktury zadań

Dzienniki rozszerzenia Durable są przydatne do zrozumienia zachowania logiki aranżacji. Jednak te dzienniki nie zawsze zawierają wystarczające informacje, aby debugować problemy z wydajnością i niezawodnością na poziomie platformy. Począwszy od wersji 2.3.0 rozszerzenia Durable, dzienniki emitowane przez podstawową platformę Durable Task Framework (DTFx) są również dostępne dla kolekcji.

Podczas przeglądania dzienników emitowanych przez dtFx ważne jest, aby zrozumieć, że aparat DTFx składa się z dwóch składników: podstawowego aparatu wysyłania () i jednego z wielu obsługiwanych dostawców magazynu (DurableTask.Corerozszerzenia Durable Functions używa DurableTask.AzureStorage domyślnie, ale są dostępne inne opcje).

  • DurableTask.Core: podstawowe wykonywanie orkiestracji i dzienniki planowania niskiego poziomu oraz dane telemetryczne.
  • DurableTask.AzureStorage: dzienniki zaplecza specyficzne dla dostawcy stanu usługi Azure Storage. Te dzienniki obejmują szczegółowe interakcje z wewnętrznymi kolejkami, obiektami blob i tabelami magazynu używanymi do przechowywania i pobierania wewnętrznego stanu aranżacji.
  • DurableTask.Netherite: dzienniki zaplecza specyficzne dla dostawcy magazynu Netherite, jeśli są włączone.
  • DurableTask.SqlServer: dzienniki zaplecza specyficzne dla dostawcy magazynu Microsoft SQL (MSSQL), jeśli są włączone.

Te dzienniki można włączyć, aktualizując sekcję logging/logLevel pliku host.json aplikacji funkcji. W poniższym przykładzie pokazano, jak włączyć dzienniki ostrzegawcze i dzienniki błędów z obu DurableTask.Core systemów i DurableTask.AzureStorage:

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "DurableTask.AzureStorage": "Warning",
      "DurableTask.Core": "Warning"
    }
  }
}

Jeśli masz włączoną Szczegółowe informacje aplikacji, te dzienniki zostaną automatycznie dodane do kolekcjitrace. Możesz wyszukiwać je w taki sam sposób, jak w przypadku wyszukiwania innych trace dzienników przy użyciu zapytań Kusto.

Uwaga

W przypadku aplikacji produkcyjnych zaleca się włączenie DurableTask.Core i zastosowanie odpowiednich dzienników dostawcy magazynu (np. DurableTask.AzureStorage) przy użyciu filtru "Warning" . Wyższe filtry szczegółowości, takie jak "Information" , są bardzo przydatne do debugowania problemów z wydajnością. Jednak te zdarzenia dziennika mogą być duże i mogą znacznie zwiększyć koszty magazynowania danych w usłudze Application Szczegółowe informacje.

Poniższe zapytanie Kusto pokazuje, jak wykonywać zapytania dotyczące dzienników DTFx. Najważniejszą częścią zapytania jest where customerDimensions.Category startswith "DurableTask" to, że filtruje wyniki do dzienników w DurableTask.Core kategoriach i DurableTask.AzureStorage .

traces
| where customDimensions.Category startswith "DurableTask"
| project
    timestamp,
    severityLevel,
    Category = customDimensions.Category,
    EventId = customDimensions.EventId,
    message,
    customDimensions
| order by timestamp asc 

Wynikiem jest zestaw dzienników napisanych przez dostawców dzienników platformy Durable Task Framework.

Wyniki zapytania application Szczegółowe informacje DTFx

Aby uzyskać więcej informacji na temat dostępnych zdarzeń dziennika, zobacz dokumentację rejestrowania strukturalnego platformy Durable Task Framework w witrynie GitHub.

Rejestrowanie aplikacji

Ważne jest, aby zachować zachowanie powtarzania orkiestratora podczas pisania dzienników bezpośrednio z funkcji orkiestratora. Rozważmy na przykład następującą funkcję orkiestratora:

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

Wynikowe dane dziennika będą wyglądać podobnie do następujących przykładowych danych wyjściowych:

Calling F1.
Calling F1.
Calling F2.
Calling F1.
Calling F2.
Calling F3.
Calling F1.
Calling F2.
Calling F3.
Done!

Uwaga

Należy pamiętać, że podczas gdy dzienniki twierdzą, że są wywoływane nazwy F1, F2 i F3, te funkcje są wywoływane tylko po raz pierwszy. Kolejne wywołania wykonywane podczas odtwarzania są pomijane, a dane wyjściowe są odtwarzane do logiki orkiestratora.

Jeśli chcesz tylko zapisywać dzienniki w wykonaniach nieodtworzania, możesz napisać wyrażenie warunkowe w celu rejestrowania tylko wtedy, gdy flaga "jest odtwarzana" to false. Rozważmy powyższy przykład, ale tym razem za pomocą testów odtwarzania.

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    if (!context.IsReplaying) log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    if (!context.IsReplaying) log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    if (!context.IsReplaying) log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

Począwszy od rozszerzenia Durable Functions 2.0, funkcje orkiestratora platformy .NET mają również możliwość utworzenia modułu ILogger , który automatycznie filtruje instrukcje dziennika podczas odtwarzania. To automatyczne filtrowanie odbywa się przy użyciu interfejsu API IDurableOrchestrationContext.CreateReplay Sejf Logger(ILogger).

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log = context.CreateReplaySafeLogger(log);
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

Uwaga

Poprzednie przykłady języka C# dotyczą rozszerzenia Durable Functions 2.x. W przypadku rozszerzenia Durable Functions 1.x należy użyć funkcji DurableOrchestrationContextIDurableOrchestrationContextzamiast . Aby uzyskać więcej informacji na temat różnic między wersjami, zobacz artykuł Wersje rozszerzenia Durable Functions.

Po wprowadzeniu wcześniej wymienionych zmian dane wyjściowe dziennika są następujące:

Calling F1.
Calling F2.
Calling F3.
Done!

Stan niestandardowy

Niestandardowy stan orkiestracji umożliwia ustawienie niestandardowej wartości stanu dla funkcji orkiestratora. Ten stan niestandardowy jest następnie widoczny dla klientów zewnętrznych za pośrednictwem interfejsu API zapytania stanu HTTP lub za pośrednictwem wywołań interfejsu API specyficznych dla języka. Stan orkiestracji niestandardowej umożliwia bogatsze monitorowanie funkcji orkiestratora. Na przykład kod funkcji orkiestratora może wywołać interfejs API "ustaw stan niestandardowy", aby zaktualizować postęp długotrwałej operacji. Klient, taki jak strona internetowa lub inny system zewnętrzny, może okresowo wysyłać zapytania do interfejsów API zapytań o stan HTTP, aby uzyskać bardziej zaawansowane informacje o postępie. Poniżej przedstawiono przykładowy kod ustawiania niestandardowej wartości stanu w funkcji orkiestratora:

[FunctionName("SetStatusTest")]
public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // ...do work...

    // update the status of the orchestration with some arbitrary data
    var customStatus = new { completionPercentage = 90.0, status = "Updating database records" };
    context.SetCustomStatus(customStatus);

    // ...do more work...
}

Uwaga

Poprzedni przykład w języku C# dotyczy rozszerzenia Durable Functions 2.x. W przypadku rozszerzenia Durable Functions 1.x należy użyć funkcji DurableOrchestrationContextIDurableOrchestrationContextzamiast . Aby uzyskać więcej informacji na temat różnic między wersjami, zobacz artykuł Wersje rozszerzenia Durable Functions.

Gdy orkiestracja jest uruchomiona, klienci zewnętrzni mogą pobrać ten stan niestandardowy:

GET /runtime/webhooks/durabletask/instances/instance123?code=XYZ

Klienci otrzymają następującą odpowiedź:

{
  "runtimeStatus": "Running",
  "input": null,
  "customStatus": { "completionPercentage": 90.0, "status": "Updating database records" },
  "output": null,
  "createdTime": "2017-10-06T18:30:24Z",
  "lastUpdatedTime": "2017-10-06T19:40:30Z"
}

Ostrzeżenie

Ładunek stanu niestandardowego jest ograniczony do 16 KB tekstu JSON UTF-16, ponieważ musi być w stanie zmieścić się w kolumnie usługi Azure Table Storage. Jeśli potrzebujesz większego ładunku, możesz użyć magazynu zewnętrznego.

Śledzenie rozproszone

Śledzenie rozproszone śledzi żądania i pokazuje, jak różne usługi współdziałają ze sobą. W usłudze Durable Functions koreluje również aranżacje i działania. Jest to pomocne, aby zrozumieć, ile czasu zajmuje aranżacja w stosunku do całej aranżacji. Warto również zrozumieć, gdzie aplikacja ma problem lub gdzie został zgłoszony wyjątek. Ta funkcja jest obsługiwana dla wszystkich języków i dostawców magazynu.

Uwaga

Śledzenie rozproszone w wersji 2 wymaga rozszerzenia Durable Functions w wersji 2.12.0 lub nowszej. Ponadto śledzenie rozproszone w wersji 2 jest w stanie wersji zapoznawczej i dlatego niektóre wzorce durable functions nie są instrumentowane. Na przykład operacje trwałe jednostek nie są instrumentowane, a ślady nie będą wyświetlane w aplikacji Szczegółowe informacje.

Konfigurowanie śledzenia rozproszonego

Aby skonfigurować śledzenie rozproszone, zaktualizuj host.json i skonfiguruj zasób Szczegółowe informacje aplikacji.

host.json

"durableTask": {
  "tracing": {
    "distributedTracingEnabled": true,
    "Version": "V2"
  }
}

Szczegółowe dane dotyczące aplikacji

Jeśli aplikacja funkcji nie jest skonfigurowana przy użyciu zasobu Application Szczegółowe informacje, skonfiguruj ją zgodnie z instrukcjami podanymi tutaj.

Sprawdzanie śladów

W zasobie Application Szczegółowe informacje przejdź do pozycji Wyszukiwanie transakcji. W wynikach sprawdź, czy zdarzenia DependencyRequest zaczynają się od prefiksów specyficznych dla rozszerzenia Durable Functions (np. orchestration:, activity:itp.). Wybranie jednego z tych zdarzeń spowoduje otwarcie wykresu Gantta, który pokaże koniec do końca rozproszonego śledzenia.

Wykres Gantta przedstawiający śledzenie rozproszone Szczegółowe informacje aplikacji.

Rozwiązywanie problemów

Jeśli nie widzisz śladów w aplikacji Szczegółowe informacje, pamiętaj, aby poczekać około pięciu minut po uruchomieniu aplikacji, aby upewnić się, że wszystkie dane są propagowane do zasobu application Szczegółowe informacje.

Debugowanie

Usługa Azure Functions obsługuje bezpośrednio kod funkcji debugowania i ta sama obsługa jest przekazywana do rozszerzenia Durable Functions, niezależnie od tego, czy działa na platformie Azure, czy lokalnie. Istnieje jednak kilka zachowań, które należy wziąć pod uwagę podczas debugowania:

  • Powtarzanie: funkcja Orchestrator regularnie powtarza się po odebraniu nowych danych wejściowych. To zachowanie oznacza, że pojedyncze logiczne wykonanie funkcji orkiestratora może spowodować wielokrotne trafienie tego samego punktu przerwania, zwłaszcza jeśli jest ono ustawione na początku kodu funkcji.
  • Await: za każdym razem, gdy wystąpi błąd await w funkcji orkiestratora, zwraca kontrolę z powrotem do dyspozytora platformy Durable Task Framework. Jeśli napotkano go po raz pierwszyawait, skojarzone zadanie nigdy nie zostanie wznowione. Ponieważ zadanie nigdy nie jest wznawiane, przechodzenie przez oczekiwanie (F10 w programie Visual Studio) nie jest możliwe. Przechodzenie do kroku działa tylko wtedy, gdy zadanie jest odtwarzane.
  • Limity czasu obsługi komunikatów: funkcja Durable Functions wewnętrznie używa komunikatów kolejek do wykonywania funkcji orkiestratora, działania i jednostki. W środowisku z wieloma maszynami wirtualnymi włamanie do debugowania przez dłuższy czas może spowodować, że inna maszyna wirtualna odebrała komunikat, co spowoduje zduplikowanie wykonania. To zachowanie istnieje również w przypadku zwykłych funkcji wyzwalacza kolejki, ale ważne jest, aby wskazać w tym kontekście, ponieważ kolejki są szczegółami implementacji.
  • Zatrzymywanie i uruchamianie: komunikaty w funkcjach Durable są utrwalane między sesjami debugowania. Jeśli zatrzymasz debugowanie i zakończysz proces hosta lokalnego podczas wykonywania funkcji trwałej, ta funkcja może zostać wykonana ponownie automatycznie w przyszłej sesji debugowania. To zachowanie może być mylące, jeśli nie jest oczekiwane. Użycie nowego centrum zadań lub wyczyszczenie zawartości centrum zadań między sesjami debugowania jest jedną z technik, aby uniknąć tego zachowania.

Napiwek

W przypadku ustawiania punktów przerwania w funkcjach orkiestratora, jeśli chcesz przerwać tylko wykonywanie nieodtwarzania, można ustawić warunkowy punkt przerwania, który przerywa tylko wtedy, gdy wartość "jest odtwarzana" to false.

Storage

Domyślnie rozszerzenie Durable Functions przechowuje stan w usłudze Azure Storage. To zachowanie oznacza, że można sprawdzić stan aranżacji przy użyciu narzędzi, takich jak Eksplorator usługi Microsoft Azure Storage.

zrzut ekranu Eksplorator usługi Azure Storage

Jest to przydatne do debugowania, ponieważ zobaczysz, w jakim stanie może znajdować się aranżacja. Komunikaty w kolejkach można również zbadać, aby dowiedzieć się, jaka praca jest oczekująca (lub zablokowana w niektórych przypadkach).

Ostrzeżenie

Chociaż jest to wygodne, aby wyświetlić historię wykonywania w magazynie tabel, unikaj podejmowania zależności od tej tabeli. Może się to zmienić w miarę rozwoju rozszerzenia Durable Functions.

Uwaga

Innych dostawców magazynu można skonfigurować zamiast domyślnego dostawcy usługi Azure Storage. W zależności od dostawcy magazynu skonfigurowanego dla aplikacji może być konieczne użycie różnych narzędzi do sprawdzenia stanu bazowego. Aby uzyskać więcej informacji, zobacz dokumentację dostawców magazynu durable functions.

Durable Functions Monitor

Durable Functions Monitor to graficzne narzędzie do monitorowania, zarządzania i debugowania wystąpień jednostek oraz zarządzania nimi. Jest ona dostępna jako rozszerzenie programu Visual Studio Code lub autonomiczna aplikacja. Informacje o konfigurowaniu i liście funkcji można znaleźć w tej witrynie typu wiki.

Przewodnik rozwiązywania problemów z usługą Durable Functions

Aby rozwiązać typowe objawy problemu, takie jak blokowanie aranżacji, brak uruchamiania, powolne działanie itp., zapoznaj się z tym przewodnikiem rozwiązywania problemów.

Następne kroki