# server\_migration

## server\_migration サンプル

<figure><img src="/files/hLURzARCEF8NthjMTb9q" alt=""><figcaption></figcaption></figure>

## 概要

Diarkis サーバはサーバクラスタとして構成されており、スケールインなどで接続中のサーバが停止した場合、別のサーバへ接続しなおすサーバマイグレーションが発生することがあります。 サーバマイグレーションを実現するにあたりクライアント側でも対応実装を行う必要があるため、本サンプルではどのような実装が必要となるか説明します。\
マイグレーションに関する詳細については[こちらのページ](/diarkis-client/diarkis-module/migration.md)を参照してください。

## ローカル環境でサーバーを起動する

サンプルで使用するサーバーを起動するためのチュートリアルを実施して、ローカル環境で Diarkis サーバーを起動します。 本サンプルではマイグレーションを発生させるため、サンプル実行中に UDP サーバの起動と停止を行う必要があります。 チュートリアルの手順を参考にサンプルコードのコメントに従って UDP サーバのプロセスを操作してください。

[Diarkis サーバをローカルで起動する](/getting-started/tutorial/setup-local-server.md)

## サンプルの引数

サンプルの起動時には以下の３つのパラメータを指定してください。

| 引数         | 説明                            |
| ---------- | ----------------------------- |
| serverAddr | Diarkis サーバのエンドポイントを指定してください  |
| UID        | 接続するユーザーの ID を任意の文字列で指定してください |
| clientKey  | クライアントキーを任意の文字列で指定してください      |

**起動例：**

`server_migration.exe 192.168.1.123:7000 1111 AAAA`

### 起動方法

本サンプルは単体で実行することができ、起動すると指定された Diarkis サーバに接続し、マイグレーションが発生するまで待機します。 マイグレーションを発生させるには Diarkis サーバを起動している PC で移動先として新たに UDP サーバを起動したのちに、接続中の UDP サーバを停止します。

## サンプルコード説明

### **UDP サーバのマイグレーション対応実装**

`DiarkisUdpBase` クラスの仮想関数をオーバーライドしてマイグレーション対応コードを実装します。

```
class DiarkisUdpServerMigrationSample : public DiarkisUdpBase
{
    ...
```

以下の実装がマイグレーション対応に関連するコードとなります。`DiarkisUdpBase::OnOffline` でサーバが停止することを検出し、アプリの都合に合わせて `DiarkisUdpBase::SendMigrate` を実行します。 `DiarkisUdpBase::SendMigrate` 実行後、Diarkis ランタイムが自動的に接続中のサーバからの切断と新しいサーバへの再接続処理を実行します。 この再接続処理の中で `DiarkisUdpBase::OnConnect` と `DiarkisUdpBase::OnDisconnect` が発火し、再接続の完了を検出することができます。

```
    void OnConnect(const DiarkisConnectionEventArgs& args) override
    {
        // OnConnect is called when a connection is established to the UDP server.
        // In this sample, this callback is called when connecting to the UDP server initially or reconnecting by the migration process.
        // OnConnect は UDP サーバへの接続が確立したタイミングで呼び出されます。
        // 本サンプルでは UDP サーバへの初回接続時とマイグレーションでの再接続時に呼び出されます。
        DiarkisUdpBase::OnConnect(args);
        DiarkisUtils::Print("Connected to UDP server status=%d reconnect=%d", args.GetStatus(), args.GetReconnect());
        if (isMigrationStarted_)
        {
            isMigrationCompleted_ = true;
        }
        isMigrationStarted_ = false;
    }
    void OnDisconnect(bool isReconnect) override
    {
        // OnDisconnect is called when disconnecting from the UDP server.
        // In this sample, this callback is called when disconnecting by the migration process and disconnecting finally.
        // OnDisconnect は UDP サーバから切断されたタイミングで呼び出されます。
        // 本サンプルではマイグレーションでの再接続時と最終的な切断時に呼び出されます。
        DiarkisUdpBase::OnDisconnect(isReconnect);
        DiarkisUtils::Print("Disconnected from UDP server reconnect=%d", isReconnect);

        // If isReconnect is true, it means the server is reconnecting.
        // サーバへの再接続時の呼び出しの場合、isReconnect が true になります。
        if (isReconnect)
        {
            // There is nothing to do for the application implementation in the reconnecting process because
            // Diarkis client runtime will reconnect to the server automatically.
            // Please be carefull if doing the disconnection process of the application in the reconnecting process.
            // マイグレーションによる再接続処理では自動的にサーバの再接続が行われるため、アプリ側では何も対応する必要はありません。
            // アプリ側の通常の切断時の処理が実行されないようにご注意ください。
        }
    }
    void OnOffline(void) override
    {
        DiarkisUdpBase::OnOffline();
        DiarkisUtils::Print("DiarkisUdpServerMigrationSample::OnOffline is called");
        // This callback is triggered when it is determined that the server will be stopped due to scaling in.
        // Please call SendMigrate at an appropriate timing according to the application's implementation to move a new server.
        // During the server migration process, the connection to the server will be temporarily disconnected,
        // and communication with the server will not be possible until reconnection is complete.
        // In this sample code, SendMigrate is called immediately within this callback for simplicity.
        // サーバがスケールインなどで停止することが決定したタイミングでこのコールバックが発火します。
        // アプリ側の実装に合わせて、適したタイミングで SendMigrate を呼び出してサーバの移動を行ってください。
        // サーバの移動処理中はサーバとの接続が一時的に切断され再接続されるまでサーバと通信できない期間が発生しますので
        // アプリの仕様に合わせて適切なタイミングで SendMigrate を呼び出してください。
        // サンプルコードでは特に考慮せず、このコールバック内で即座に SendMigrate を呼び出しています。
        this->SendMigrate();
        isMigrationStarted_ = true;
    }

```

### **Room のマイグレーション対応実装**

Room を使用している場合、マイグレーションを行うには Room 専用の対応実装を行う必要があります。 `DiarkisRoomBase` クラスの仮想関数をオーバーライドしてマイグレーション対応コードを実装します。

```
class DiarkisRoomServerMigrationSample : public DiarkisRoomBase
{
    ...
```

以下の実装が Room のマイグレーション対応に関連するコードとなります。構造としては UDP サーバのマイグレーション対応実装と同様になっていますが使用するコールバックが異なります。

```
    void OnRoomMigrateStart(void) override
    {
        // This callback is triggered when migration is started on the server side.
        // There is no need to perform any special processing on the application side, but if you want to recognize that migration has started, please use this callback.
        // サーバ側でマイグレーションが開始されたタイミングでこのコールバックが発火します。
        // アプリ側で何か特別な処理を行う必要はありませんが、マイグレーションが開始されたことを認識したい場合はこのコールバックを利用してください。
        DiarkisRoomBase::OnRoomMigrateStart();
        DiarkisUtils::Print("The room migration is started...");
        isMigrationStarted_ = true;
    }

    void OnRoomMigrateComplete(const DiarkisRoomMigrateCompleteEventArgs& e) override
    {
        // This callback is triggered when migration is completed on the server side.
        // There is no need to perform any special processing on the application side, but if you want to recognize that migration has completed, please use this callback.
        // サーバ側でマイグレーションが完了したタイミングでこのコールバックが発火します。
        // アプリ側で何か特別な処理を行う必要はありませんが、マイグレーションが完了したことを認識したい場合はこのコールバックを利用してください。
        DiarkisRoomBase::OnRoomMigrateComplete(e);

        if (e.IsSuccess() == false)
        {
            DiarkisUtils::Print("Failed to Migrate. error code=%d message=%s", e.GetErrorCode(), e.GetErrorMessage().c_str());
            return;
        }

        DiarkisUtils::Print("The room migration is completed...\nsuccess=%d, RoomID=%s", e.IsSuccess(), e.GetRoomID().c_str());
        if (isMigrationStarted_)
        {
            isMigrationCompleted_ = true;
        }
    }

    void OnOffline() override
    {
        DiarkisRoomBase::OnOffline();
        DiarkisUtils::Print("DiarkisRoomServerMigrationSample::OnOffline is called");

        // This callback is triggered when it is determined that the server will be stopped due to scaling in.
        // Please call SendMigrate at an appropriate timing according to the application's implementation to move a new server(Room).
        // During the server migration process, the connection to the server will be temporarily disconnected,
        // and communication with the server will not be possible until reconnection is complete.
        // Also, please note that only the owner of the Room can call SendMigrateRoom.
        // In this sample code, SendMigrate is called immediately within this callback for simplicity.
        // サーバがスケールインなどで停止することが決定したタイミングでこのコールバックが発火します。
        // アプリ側の実装に合わせて、適したタイミングで SendMigrate を呼び出してサーバ(Room)の移動を行ってください。
        // サーバの移動処理中はサーバとの接続が一時的に切断され再接続されるまでサーバと通信できない期間が発生しますので
        // アプリの仕様に合わせて適切なタイミングで SendMigrate を呼び出してください。
        // また、Room のオーナーのみが SendMigrateRoom を呼び出すことができますのでご注意ください。
        // サンプルコードでは特に考慮せず、このコールバック内で即座に SendMigrate を呼び出しています。
        if (GetOwnUID() == GetOwnerUID())
        {
            // Only the owner of the Room calls Migrate
            // Room のオーナーが Migrate を呼ぶ
            this->SendMigrateRoom();
        }
    }
```

### **マイグレーションを発生させる手順**

ローカルで Diarkis サーバを立ち上げている場合、UDP サーバが複数プロセス起動している状態で、クライアントが接続中の UDP サーバを停止させることでマイグレーションを発生させることができます。 サンプル起動時には 1 つだけ UDP サーバを起動しておくとクライアントの接続先サーバプロセスが固定されるため、クライアント接続後に新たに UDP サーバのプロセスを起動した際に、どのプロセスを停止すればよいかが判別しやすくなります。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.diarkis.io/diarkis-client/samples/cpp/server_migration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
