# エラー処理

> Handle errors in your modules using error codes and custom error-handling logic.

モジュール内でエラーを処理する方法を説明します。

## エラーコード##error-codes

Cloud Code は、モジュールが例外をスローした場合に `422` ステータスエラーを返します。

エラー処理ロジックでは、Cloud Code API エラーレスポンスから返されるエラーメッセージのかわりにエラーコードまたはエラータイプを使用します。エラーメッセージは将来変更される可能性がありますが、エラーコードとタイプは同じままになります。

## エラーのラップ##error-wrapping

エラーを処理するにはコードを `try`/`catch` ブロックにラップします。エラーが発生した場合は、それをログに記録し、クライアントにエラーを返すことができます。

例えば、ラップされない関数を使用できます。

```csharp
    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,  ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));
    }
```

ラップされない関数はジェネリックエラーを返します。

```json
{
  "type": "problems/invocation",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invocation Error",
  "instance": null,
  "code": 9009,
  "details": [
    {
      "message": "Error executing Cloud Code function. Exception type: ApiException. Message: Bad Request",
      "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
      "stackTrace": [
        "at Unity.Services.CloudCode.Shared.HttpApiClient.ToApiResponse[T](HttpResponseMessage response)",
        "at Unity.Services.CloudCode.Shared.HttpApiClient.SendAsync[T](String path, HttpMethod method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken)",
        "at Unity.Services.Economy.Api.EconomyCurrenciesApi.IncrementPlayerCurrencyBalanceAsync(IExecutionContext executionContext, String accessToken, String projectId, String playerId, String currencyId, CurrencyModifyBalanceRequest currencyModifyBalanceRequest, String configAssignmentHash, String unityInstallationId, String analyticsUserId, CancellationToken cancellationToken)",
        "at Sample.HelloWorld.IncrementBalanceUnhandled(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 148"
      ]
    }
  ]
}
```

`try`/`catch` ブロックを追加してエラーを処理する場合は、より具体的なエラーメッセージを返すことができます。エラーをログに記録することもできます。

```csharp
    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
            return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

        }
        catch (ApiException e)
        {
             _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }
```

ラップされた関数は、エラーメッセージをより詳しい情報とともに返します。

```json
{
    "type": "problems/invocation",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invocation Error",
    "instance": null,
    "code": 9009,
    "details": [
        {
            "message": "Error executing Cloud Code function. Exception type: Exception. Message: Failed to increment balance for playerId 7wCG6G0d1PU6WSVZPG9oQ1op97xd. Error: Bad Request",
            "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
            "stackTrace": [
                "at Sample.HelloWorld.IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 165"
            ]
        }
    ]
}
```

[Unity Dashboard](https://cloud.unity.com) でログを確認できます。エラーに関する詳細を取得するには、**Products** (製品) > **Cloud Code** > **Logs** (ログ) を選択します。

## リクエストのバッチ処理によるエラー処理##error-handling-with-batch-requests

リクエストのバッチ処理の詳細については、[リクエストのバッチ処理](./batch-requests.md) を参照してください。

## ステータスコード##status-codes

Cloud Code C# SDK が不成功のステータスコードを返すたびに、SDK は `ApiException` 例外をスローします。この例外を使用して、ステータスコードとエラーメッセージを取得できます。

`ApiException` 例外を捕捉して処理するか、エラーをログに記録して再スローできます。これは、`ApiResponse` オブジェクト内でステータスコードを確認する必要がないことを意味します。

## 処理されないエラー##unhandled-errors

Cloud Code は、無限ループなどのメモリリークに起因する例外を処理できません。モジュールがメモリ制限を超えると、ワーカーは最終的にクラッシュします。Cloud Code は `async void` パターンの例外を処理できません。常に `Task` または `Task<T>` を返します。非同期プログラミングのベストプラクティスについては、[Microsoft の公式ドキュメント](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming) を参照してください。

## ロギング##logging

モジュールのデバッグに役立てるために、エラーと警告を `ILogger` インターフェースでログに記録できます。

Cloud Code は、`playerId`、`environmentId`、`projectId` のような属性をログに自動的に追加するため、それらをログメッセージに追加する必要はありません。

```csharp
public class HelloWorld
{
    private readonly ILogger<HelloWorld> _logger;
    public HelloWorld(ILogger<HelloWorld> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
           var res =  await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

           _logger.LogInformation("Incremented currency {currencyId} balance by {amount}", currencyId, 10);
           return res;

        }
        catch (ApiException e)
        {
            _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.Dependencies.AddSingleton(GameApiClient.Create());
        }
    }
}
```

さまざまなレベルでメッセージをログに記録できます。これらのレベルは Unity Dashboard でログをクエリするのに役立ちます。

```csharp
    _logger.LogDebug("debug message");
    _logger.LogInformation("info message");
    _logger.LogWarning("warning message");
    _logger.LogError("error message");
    _logger.LogCritical("critical message");
```

ログの表示とフィルター処理を行うには、[Unity Dashboard](https://cloud.unity.com) に移動し、**Products** (製品) > **Cloud Code** > **Logs** (ログ) を選択します。

詳細については、[ログの発行](../../logging/tutorials/emit-logs#cloud-code-c-modules) を参照してください。
