# 오류 처리

> 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)를 참고하십시오.
