# リクエストのバッチ処理

> Batch your requests to execute UGS service calls in parallel for efficiency.

UGS サービスを呼び出すとリクエストをバッチ処理し、並行して実行できます。

`Task.WhenAll` メソッドを使用すると UGS サービスを並行して呼び出すことができます。このメソッドは、引数リストのすべてのタスクが完了したときに、`Task` を返します。

> **Note:**
>
> **ノート:** 失敗したリクエストすべてがログに記録されます。これらは、Unity Dashboard の Cloud Code ログで確認できます。ロギングの詳細については、[ロギング](../../logging/overview) を参照してください。

> **Note:**
>
> **ノート:** 一部のリクエストが失敗した場合、成功したリクエストはロールバックされません。

## 呼び出して結果を返す##call-and-return-results

以下のサンプルを使用し、サービスを呼び出して、リクエストの結果を返すことができます。

以下のサンプルは、Leaderboards サービスと Economy サービスへの呼び出しを行います。リーダーボードまたは通貨をプロジェクトで設定していない場合、これらの呼び出しは失敗します。これを使用して、Cloud Code モジュールでのエラー処理をテストできます。

このメソッドから返されるのは、リクエストの結果とメソッドのシグネチャを含むディクショナリです (リクエストがキー、リクエストの結果が値です)。リクエストが失敗した場合、これによって、失敗したリクエストが示されます。これらの失敗もログに記録されます。

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudSave.Model;
using Unity.Services.Economy.Model;

namespace BatchingRequests;

public class BatchingRequests
{
    private const string ExperienceKey = "experience";
    private const string ProgressXpKey = "progressXP";
    private const string FailedMessage = "Failed. Check logs.";

    private readonly ILogger<BatchingRequests> _logger;
    public BatchingRequests(ILogger<BatchingRequests> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("HandleMultipleRequests")]
    public async Task<Dictionary<string, object>> HandleMultipleRequests(IGameApiClient gameApiClient, IExecutionContext ctx)
    {
        async Task<object>  GetCloudSaveData()
        {
           var res = await gameApiClient.CloudSaveData.GetItemsAsync(ctx, ctx.AccessToken, ctx.ProjectId, ctx.PlayerId, new List<string> { ExperienceKey, ProgressXpKey });
           return res.Data;
        }

        async Task<object>  SetCloudSaveData()
        {
            var res = await gameApiClient.CloudSaveData.SetItemAsync(ctx, ctx.AccessToken, ctx.ProjectId, ctx.PlayerId, new SetItemBody(ExperienceKey, 1));
            return res.Data;
        }
        async Task<object>  GetLeaderboardScore()
        {
            const string leaderboardId = "leaderboard";
            var res = await gameApiClient.Leaderboards.GetLeaderboardPlayerScoreAsync(ctx, ctx.AccessToken, Guid.Parse(ctx.ProjectId), leaderboardId, ctx.PlayerId);
            return res.Data;
        }

        async Task<object>  GetEconomyConfig()
        {
            var res = await gameApiClient.EconomyConfiguration.GetPlayerConfigurationAsync(ctx, ctx.AccessToken, ctx.ProjectId, ctx.PlayerId);
            return res.Data;
        }

        async Task<object> SetEconomyConfig()
        {
            const string currencyId = "NOT_REAL";
            var res = await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.AccessToken, ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 1));
            return res.Data;
        }

        // Create a list of UGS tasks that return data
        var tasksWithObjects = new List<Func<Task<object>>>() { GetCloudSaveData, GetLeaderboardScore, SetCloudSaveData, GetEconomyConfig, SetEconomyConfig };
        var results = await AwaitBatch(tasksFns);

        foreach (var item in results)
        {
            if (item is Exception)
            {
                _logger.LogError($"AwaitBatch failed status {item}");
            }
            else if (item is CurrencyBalanceResponse)
            {
                _logger.LogInformation($"AwaitBatch CurrencyBalanceResponse status {item.GetType()} = {item}");
            }
            else
            {
                _logger.LogInformation($"AwaitBatch success status {item.GetType()} = {item}");
            }
        }
        // Alternatively to looping through all results, you may access function results directly
        // The order of function results follows the order of the function input e.g.
        // - GetCloudSaveData corresponds to results[0]: GetItemsResponse || Exception
        // - GetLeaderboardScore corresponds to results[1]: LeaderboardEntryWithUpdatedTime || Exception
        // ... etc
        // This can also help ascertain where the Exception originated from
    }

    private async Task<object[]> AwaitBatch(List<Func<Task<object>>> tasks)
    {
        var tasksToRun = tasks.Select(Run);
        var results = await Task.WhenAll(tasksToRun);
        return results;
    }

    async Task<object> Run(Func<Task<object>> fn)
    {
        try
        {
            return await fn();
        }
        catch (Exception e)
        {
            return e;
        }
    }
}

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