Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A Durable Functions vezényléseket kódban implementálhatja, így a nyelv beépített hibakezelési funkcióit használhatja. A hibakezelés és a kompenzáció nem igényel új fogalmakat, de néhány vezénylési viselkedésről érdemes tudni.
Megjegyzés:
Az Azure Functions Node.js programozási modelljének 4. verziója általánosan elérhető. A v4-es modell úgy lett kialakítva, hogy rugalmasabb és intuitívabb élményt nyújtson a JavaScript- és TypeScript-fejlesztők számára. A v3 és a v4 közötti különbségekről további információt a migrálási útmutatóban talál.
A következő kódrészletekben a JavaScript (PM4) a v4-es programozási modellt, az új élményt jelöli.
A felhőszolgáltatásokat használó alkalmazásoknak kezelni kell a hibákat, és az ügyféloldali újrapróbálkozások fontos részét képezik a tervezésnek. A Durable Task SDK-k támogatják a hibakezelést, az újrapróbálkozásokat és az időtúllépéseket a robusztus munkafolyamatok létrehozásához.
Tevékenységfüggvények és alvezérlések hibáinak kezelése
Durable Functions esetében a tevékenységfüggvényeken vagy alvezényléseken belül felmerülő kezeletlen kivételeket szabványos kivételtípusok használatával visszaküldik a vezénylő függvényhez.
A következő orchestrator függvény két számla között utal át pénzt:
Izolált munkavállalói modell
A Durable Functions C# izolált, nem kezelt kivételei TaskFailedException néven jelennek meg.
A kivételüzenet általában azonosítja, hogy mely tevékenységfüggvények vagy al-vezénylések okozták a hibát. A részletesebb hibainformációk eléréséhez vizsgálja meg a FailureDetails tulajdonságot .
[FunctionName("TransferFunds")]
public static async Task Run(
[OrchestrationTrigger] TaskOrchestrationContext context, TransferOperation transferDetails)
{
await context.CallActivityAsync("DebitAccount",
new
{
Account = transferDetails.SourceAccount,
Amount = transferDetails.Amount
});
try
{
await context.CallActivityAsync("CreditAccount",
new
{
Account = transferDetails.DestinationAccount,
Amount = transferDetails.Amount
});
}
catch (TaskFailedException)
{
// Refund the source account.
// Another try/catch could be used here based on the needs of the application.
await context.CallActivityAsync("CreditAccount",
new
{
Account = transferDetails.SourceAccount,
Amount = transferDetails.Amount
});
}
}
Megjegyzés:
- A kivételüzenet általában azonosítja, hogy mely tevékenységfüggvények vagy al-vezénylések okozták a hibát. A részletesebb hibainformációk eléréséhez vizsgálja meg a tulajdonságot
FailureDetails. - Alapértelmezés szerint tartalmazza a
FailureDetails, a hibaüzenetet, a veremkövetést és a beágyazott belső kivételeket (mindegyik rekurzív objektumként van jelölveFailureDetails). Ha további egyéni kivételtulajdonságokat szeretne felvenni a hibakimenetbe, tekintse meg a Hibakezelési Részletek egyéni kivétel tulajdonságainak felvétele (.NET izolált) című témakört.
Fontos
Migrálási megjegyzés (folyamatban az elkülönítéshez): A folyamatban lévő modellben FunctionFailedException.InnerException a tevékenység által elvetett eredeti kivételobjektumot tartalmazza, amelyet közvetlenül vethet és vizsgálhat meg. Az izolált feldolgozói TaskFailedException nem tartalmazza az eredeti kivételt InnerException. Ehelyett a hiba részletei csak a FailureDetails tulajdonságon keresztül érhetők el, amely sztringalapú tulajdonságokat (ErrorType, ErrorMessage, StackTrace) biztosít. Az eredeti kivételobjektumot nem lehet közvetlenül leadni vagy elérni. Az eredeti kivételtípus ellenőrzésére használható FailureDetails.IsCausedBy<T>() .
Folyamaton belüli modell
A Durable Functions C# in-process használata esetén a nem kezelt kivételek FunctionFailedException néven jelennek meg.
A kivételüzenet általában tartalmazza a sikertelen tevékenységfüggvényt vagy al-orkesztrációt. A részletekért ellenőrizze a következőt: InnerException.
[FunctionName("TransferFunds")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
var transferDetails = context.GetInput<TransferOperation>();
await context.CallActivityAsync("DebitAccount",
new
{
Account = transferDetails.SourceAccount,
Amount = transferDetails.Amount
});
try
{
await context.CallActivityAsync("CreditAccount",
new
{
Account = transferDetails.DestinationAccount,
Amount = transferDetails.Amount
});
}
catch (FunctionFailedException)
{
// Refund the source account.
// Another try/catch could be used here based on the needs of the application.
await context.CallActivityAsync("CreditAccount",
new
{
Account = transferDetails.SourceAccount,
Amount = transferDetails.Amount
});
}
}
Megjegyzés:
Az előző C#-példák Durable Functions 2.x-et használnak. Az 1.x Durable Functions esetében a DurableOrchestrationContext használatát IDurableOrchestrationContext helyett kell alkalmazni. A verzióeltéréseket a Durable Functions verziók cikkben találja.
Ha az első CreditAccount függvényhívás meghiúsul, a vezénylő függvény kompenzálja az összeget a forrásfiókba történő jóváírással.
A Durable Task SDK-kban a tevékenységek vagy alvezénylések során felmerülő kezeletlen kivételeket a rendszer visszaállítja a vezénylőhöz a TaskFailedException típus használatával. A kivétel tulajdonsága FailureDetails részletes információkat nyújt a hibáról.
using Microsoft.DurableTask;
[DurableTask(nameof(TransferFundsOrchestration))]
public class TransferFundsOrchestration : TaskOrchestrator<TransferOperation, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, TransferOperation transfer)
{
await context.CallActivityAsync(
nameof(DebitAccountActivity),
new AccountOperation { Account = transfer.SourceAccount, Amount = transfer.Amount });
try
{
await context.CallActivityAsync(
nameof(CreditAccountActivity),
new AccountOperation { Account = transfer.DestinationAccount, Amount = transfer.Amount });
}
catch (TaskFailedException ex)
{
// Log the failure details
var details = ex.FailureDetails;
// Compensate by refunding the source account
await context.CallActivityAsync(
nameof(CreditAccountActivity),
new AccountOperation { Account = transfer.SourceAccount, Amount = transfer.Amount });
return $"Transfer failed: {details.ErrorMessage}. Compensation completed.";
}
return "Transfer completed successfully";
}
}
Ha a CreditAccount tevékenység meghiúsul, a vezénylő elkapja a kivételt, és a kompenzálást az összeg forrásfiókba történő jóváírásával hajtja végre.
Hibák kezelése több tevékenységhívással (kiterjesztés/beépítés)
Ha Task.WhenAll több tevékenységhívást futtat párhuzamosan (fan-out/fan-in minta), és egy vagy több tevékenység sikertelen lesz, await csak az első kivételt veti ki. Az összes hiba eléréséhez vizsgálja meg a
Izolált munkavállalói modell
var tasks = new[]
{
context.CallActivityAsync("Activity1", input1),
context.CallActivityAsync("Activity2", input2),
context.CallActivityAsync("Activity3", input3),
};
var allTask = Task.WhenAll(tasks);
try
{
await allTask;
}
catch (TaskFailedException)
{
// 'await' rethrows only the first exception. To inspect all failures,
// check allTask.Exception, which is an AggregateException.
if (allTask.Exception != null)
{
foreach (var inner in allTask.Exception.InnerExceptions)
{
if (inner is TaskFailedException taskFailed)
{
// Use taskFailed.FailureDetails to inspect error details
var errorType = taskFailed.FailureDetails.ErrorType;
var errorMessage = taskFailed.FailureDetails.ErrorMessage;
}
}
}
}
Folyamaton belüli modell
var tasks = new[]
{
context.CallActivityAsync("Activity1", input1),
context.CallActivityAsync("Activity2", input2),
context.CallActivityAsync("Activity3", input3),
};
var allTask = Task.WhenAll(tasks);
try
{
await allTask;
}
catch (FunctionFailedException)
{
// 'await' rethrows only the first exception. To inspect all failures,
// check allTask.Exception, which is an AggregateException.
if (allTask.Exception != null)
{
foreach (var inner in allTask.Exception.InnerExceptions)
{
if (inner is FunctionFailedException funcFailed)
{
// Use funcFailed.InnerException to access the original exception
}
}
}
}
Entitásfüggvények hibáinak kezelése
Az entitásfüggvények kivételkezelése a Durable Functions üzemeltetési modelltől függ:
Izolált munkavállalói modell
Az izolált C# Durable Functions futtatókörnyezet az entitásfüggvény-kivételeket csomagolja egy EntityOperationFailedException. Az eredeti kivétel részleteinek lekéréséhez vizsgálja meg a tulajdonságot FailureDetails .
[Function(nameof(MyOrchestrator))]
public static async Task<List<string>> MyOrchestrator(
[Microsoft.Azure.Functions.Worker.OrchestrationTrigger] TaskOrchestrationContext context)
{
var entityId = new Microsoft.DurableTask.Entities.EntityInstanceId(nameof(Counter), "myCounter");
try
{
await context.Entities.CallEntityAsync(entityId, "Add", 1);
}
catch (EntityOperationFailedException ex)
{
// Add your error handling
}
return new List<string>();
}
Folyamaton belüli modell
A C# folyamaton belül működő Durable Functions esetében az entitásfüggvények visszaadják az eredeti kivételtípusokat a vezénylőnek.
[FunctionName("Function1")]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
try
{
var entityId = new EntityId(nameof(Counter), "myCounter");
await context.CallEntityAsync(entityId, "Add", 1);
}
catch (Exception ex)
{
// The exception type is InvalidOperationException with the message "this is an entity exception".
}
return string.Empty;
}
[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
switch (ctx.OperationName.ToLowerInvariant())
{
case "add":
throw new InvalidOperationException("this is an entity exception");
case "get":
ctx.Return(ctx.GetState<int>());
break;
}
}
Automatikus újrapróbálkozás hiba esetén
Amikor tevékenységfüggvényeket vagy részvezénylési függvényeket hív meg, adjon meg egy automatikus újrapróbálkozási szabályzatot. Az alábbi példa egy függvényt legfeljebb háromszor hív meg, és öt másodpercet vár az újrapróbálkozások között:
Izolált munkavállalói modell
[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context)
{
var options = TaskOptions.FromRetryPolicy(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5)));
await context.CallActivityAsync("FlakyFunction", options: options);
// ...
}
Folyamaton belüli modell
[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
await context.CallActivityWithRetryAsync("FlakyFunction", retryOptions, null);
// ...
}
Megjegyzés:
Az előző C# példák a Durable Functions 2.x verziójára vonatkoznak. Az 1.x Durable Functions esetén a DurableOrchestrationContext-t kell használni IDurableOrchestrationContext helyett. A verziók közötti különbségekről további információt a Durable Functions verzióiról szóló cikkben talál.
Az előző példában szereplő tevékenységfüggvény-hívás egy paraméterrel konfigurál egy automatikus újrapróbálkozési szabályzatot. Szabja testre a szabályzatot az alábbi beállításokkal:
- Kísérletek maximális száma: A kísérletek maximális száma. Ha 1 értékre van állítva, nem történik újrapróbálkozás.
- Első újrapróbálkozási időköz: Az első újrapróbálkozási kísérlet előtti várakozási idő.
- Visszalépési együttható: A visszalépés növekedési ütemének meghatározására használt együttható. Alapértelmezett érték: 1.
- Maximális újrapróbálkozási időköz: Az újrapróbálkozási kísérletek közötti várakozás maximális időtartama.
- Újrapróbálkozási időtúllépés: Az újrapróbálkozással töltött idő maximális száma. Alapértelmezés szerint az újrapróbálkozások határozatlan ideig folytatódnak.
A Durable Task SDK-k alternatív ütemezési módszereket tartalmaznak, amelyek egy megadott szabályzat alapján újrapróbálkoznak a sikertelen tevékenységekre. Ezek a módszerek olyan tevékenységekhez hasznosak, amelyek adatokat olvasnak webszolgáltatásokból, vagy idempotens írásokat végeznek egy adatbázisba.
using Microsoft.DurableTask;
[DurableTask(nameof(OrchestratorWithRetry))]
public class OrchestratorWithRetry : TaskOrchestrator<string, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, string input)
{
// Configure retry policy
var retryPolicy = new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5),
backoffCoefficient: 2.0,
maxRetryInterval: TimeSpan.FromMinutes(1),
retryTimeout: TimeSpan.FromMinutes(5));
var options = TaskOptions.FromRetryPolicy(retryPolicy);
// Call activity with automatic retry
string result = await context.CallActivityAsync<string>(
nameof(UnreliableActivity), input, options);
return result;
}
}
Az újrapróbálkozás szabályzatbeállításai a következők:
- Kísérletek maximális száma: Az újrapróbálkozási kísérletek maximális száma. Ha 1 értékre van állítva, nem történik újrapróbálkozás.
- Első újrapróbálkozási időköz: Az első újrapróbálkozási kísérlet előtti várakozási idő.
- Visszalépési együttható: A visszalépés növekedési ütemének meghatározására használt együttható. Alapértelmezett érték: 1.
- Maximális újrapróbálkozási időköz: Az újrapróbálkozási kísérletek közötti várakozás maximális időtartama.
- Újrapróbálkozás időtúllépése: Az újrapróbálkozással töltött idő maximális mennyisége.
Egyéni újrapróbálkozás-kezelők
A .NET és Java akkor implementálják az újrapróbálkozási kezelőket a kódban, ha a deklaratív újrapróbálkozási szabályzatok nem elég kifejezőek. Más nyelvekben az újrapróbálkozások logikáját hurkokkal, kivételkezeléssel és időzítőkkel valósíthatja meg az újrapróbálkozások közötti késleltetés érdekében.
Izolált munkavállalói modell
TaskOptions retryOptions = TaskOptions.FromRetryHandler(retryContext =>
{
// Don't retry anything that derives from ApplicationException
if (retryContext.LastFailure.IsCausedBy<ApplicationException>())
{
return false;
}
// Quit after N attempts
return retryContext.LastAttemptNumber < 3;
});
try
{
await ctx.CallActivityAsync("FlakeyActivity", options: retryOptions);
}
catch (TaskFailedException)
{
// Case when the retry handler returns false...
}
Folyamaton belüli modell
RetryOptions retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: int.MaxValue)
{
Handle = exception =>
{
// Return true to handle and retry, or false to throw.
if (exception is TaskFailedException failure)
{
// Exceptions from task activities are always this type. Inspect the
// inner exception for more details.
}
return false;
}
};
await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null);
Egyéni újrapróbálkozás-kezelők
A .NET és Java az újrapróbálkozás-kezelőket kódban implementálva szabályozza az újrapróbálkozás logikáját. Ez a megközelítés akkor hasznos, ha a deklaratív újrapróbálkozási szabályzatok nem elég kifejezőek.
using Microsoft.DurableTask;
[DurableTask(nameof(OrchestratorWithCustomRetry))]
public class OrchestratorWithCustomRetry : TaskOrchestrator<string, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, string input)
{
// Custom retry handler with conditional logic
TaskOptions retryOptions = TaskOptions.FromRetryHandler(retryContext =>
{
// Don't retry if it's a validation error
if (retryContext.LastFailure.IsCausedBy<ArgumentException>())
{
return false;
}
// Retry up to 5 times for transient errors
return retryContext.LastAttemptNumber < 5;
});
try
{
return await context.CallActivityAsync<string>(
nameof(UnreliableActivity), input, retryOptions);
}
catch (TaskFailedException)
{
// All retries exhausted
return "Operation failed after all retries";
}
}
}
Függvény időkorlátai
Ha egy függvényhívás túl sokáig tart, szakítsa meg az időzítést a vezérlő függvényben. Hozzon létre egy tartós időzítőt egy any feladatválasztóval, ahogyan az alábbi példában is látható:
Izolált munkavállalói modell
[Function("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] TaskOrchestrationContext context)
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
DateTime deadline = context.CurrentUtcDateTime.Add(timeout);
using (var cts = new CancellationTokenSource())
{
Task activityTask = context.CallActivityAsync("FlakyFunction");
Task timeoutTask = context.CreateTimer(deadline, cts.Token);
Task winner = await Task.WhenAny(activityTask, timeoutTask);
if (winner == activityTask)
{
// success case
cts.Cancel();
return true;
}
else
{
// timeout case
return false;
}
}
}
Folyamaton belüli modell
[FunctionName("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
DateTime deadline = context.CurrentUtcDateTime.Add(timeout);
using (var cts = new CancellationTokenSource())
{
Task activityTask = context.CallActivityAsync("FlakyFunction");
Task timeoutTask = context.CreateTimer(deadline, cts.Token);
Task winner = await Task.WhenAny(activityTask, timeoutTask);
if (winner == activityTask)
{
// success case
cts.Cancel();
return true;
}
else
{
// timeout case
return false;
}
}
}
Megjegyzés:
Az előző C# példák a Durable Functions 2.x verziójára vonatkoznak. Az 1.x Durable Functions esetén a DurableOrchestrationContext-t kell használni IDurableOrchestrationContext helyett. A verziók közötti különbségekről további információt a Durable Functions verzióiról szóló cikkben talál.
Megjegyzés:
Ez a mechanizmus nem vet véget a már folyamatban lévő tevékenységfüggvény-végrehajtásnak. Lehetővé teszi, hogy a vezénylő függvény figyelmen kívül hagyja az eredményt, és továbblépjön. További információ: Időzítők.
Tevékenység időtúllépései
Ha egy tevékenységhívás túl sokáig tart, abbahagyhatja a várakozást. Hozzon létre egy tartós időzítőt, és hasonlítsa össze a tevékenységi feladattal.
using Microsoft.DurableTask;
using System;
using System.Threading;
using System.Threading.Tasks;
[DurableTask(nameof(OrchestratorWithTimeout))]
public class OrchestratorWithTimeout : TaskOrchestrator<string, bool>
{
public override async Task<bool> RunAsync(
TaskOrchestrationContext context, string input)
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
DateTime deadline = context.CurrentUtcDateTime.Add(timeout);
using var cts = new CancellationTokenSource();
Task activityTask = context.CallActivityAsync(nameof(SlowActivity), input);
Task timeoutTask = context.CreateTimer(deadline, cts.Token);
Task winner = await Task.WhenAny(activityTask, timeoutTask);
if (winner == activityTask)
{
// Activity completed in time - cancel the timer
cts.Cancel();
return true;
}
else
{
// Timeout occurred
return false;
}
}
}
Megjegyzés:
Ez a mechanizmus nem vet véget a már folyamatban lévő tevékenységek végrehajtásának. Lehetővé teszi, hogy a vezénylő figyelmen kívül hagyja az eredményt, és továbblép. További információkért tekintse meg az Időzítők dokumentációját.
Kezeletlen kivételek
Ha egy vezénylő függvény nem kezelt kivétellel meghiúsul, a futtatókörnyezet naplózza a kivétel részleteit, és a példány Failed állapottal fejeződik be.
A FailureDetails egyéni kivételtulajdonságainak inkludálása (.NET elkülönített környezet)
A .NET izolált modellt használó Durable Task munkafolyamatokban a feladathibák egy FailureDetails objektumra vannak szerializálva. Alapértelmezés szerint az objektum a következő mezőket tartalmazza:
-
ErrorType—Kivételtípus neve -
Message— Kivételüzenet -
StackTrace— Szerializált verem nyomkövetése -
InnerFailure— BeágyazottFailureDetailsobjektum belső kivételekhez
A Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 verziótól kezdve ezt a viselkedést a IExceptionPropertiesProvider megvalósításával bővítheti (a Microsoft.DurableTask.Worker csomag v1.16.1 verziójától kezdődően). Ez a szolgáltató határozza meg, hogy mely kivételtípusok és tulajdonságok szerepeljenek a FailureDetails.Properties szótárban.
Megjegyzés:
- Ez a funkció csak .NET Izolált verzióban érhető el. A Java támogatása még nem érhető el.
- Győződjön meg arról, hogy a Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 vagy későbbi verzióját használja.
- Győződjön meg arról, hogy a Microsoft.DurableTask.Worker 1.16.1-s vagy újabb verzióját használja.
Kivételtulajdonság-szolgáltató implementálása
Implementáljon egy egyedi IExceptionPropertiesProvider-t, amely kivonja és visszaadja a kiválasztott tulajdonságokat a fontos kivételekhez, amelyek számítanak. A visszaadott szótár szerializálódik a Properties mező FailureDetails területére, amikor egy megfelelő kivételtípus kerül dobásra.
using Microsoft.DurableTask.Worker;
public class CustomExceptionPropertiesProvider : IExceptionPropertiesProvider
{
public IDictionary<string, object?>? GetExceptionProperties(Exception exception)
{
return exception switch
{
ArgumentOutOfRangeException e => new Dictionary<string, object?>
{
["ParamName"] = e.ParamName,
["ActualValue"] = e.ActualValue
},
InvalidOperationException e => new Dictionary<string, object?>
{
["CustomHint"] = "Invalid operation occurred",
["TimestampUtc"] = DateTime.UtcNow
},
_ => null // Other exception types not handled
};
}
}
A szolgáltató regisztrálása
A Program.cs-ban regisztrálja az egyéni IExceptionPropertiesProvider a .NET Izolált feldolgozó gazdagépen:
using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(builder =>
{
// Register custom exception properties provider
builder.Services.AddSingleton<IExceptionPropertiesProvider, CustomExceptionPropertiesProvider>();
})
.Build();
host.Run();
A szolgáltató regisztrálása után minden olyan kivétel, amely egy kezelt típusnak felel meg, automatikusan tartalmazza a konfigurált tulajdonságokat a FailureDetails szolgáltatóban.
FailureDetails-példakimenet
Amikor egy kivétel lép fel, amely megfelel a szolgáltató konfigurációjának, az orkesztáció a következőhöz hasonló szerializált FailureDetails objektumot kap:
{
"errorType": "TaskFailedException",
"message": "Activity failed with an exception.",
"stackTrace": "...",
"innerFailure": {
"errorType": "ArgumentOutOfRangeException",
"message": "Specified argument was out of range.",
"properties": {
"ParamName": "count",
"ActualValue": 42
}
}
}
Kezeletlen kivételek
Ha egy orchestrátor nem kezelt kivétel miatt meghibásodik, a futtatókörnyezet naplózza a kivétel részleteit, és a példány Failed állapottal fejeződik be.
TaskFailedException A FailureDetails tulajdonság tartalmazza a hibatípust, az üzenetet és a verem nyomkövetését.
Következő lépések
JavaScript SDK példák a GitHubon .