miso_soup3 Blog

主に ASP.NET 関連について書いています。

LaunchDarkly にてフラグが評価される前にダッシュボードを使う

LaunchDarkly では、ユーザーによってフラグが評価されるとき、同時にユーザー情報がインデックスされます。それにより、管理画面のダッシュボードからそのユーザーに関する操作を行うことができます。

しかし、ユーザーによってフラグが評価される前に、その機能を使いたいケースがあります。そのためには、Client-SDK または Server-SDK で、identifyAPI を使います。

以下のコードは、Server-SDKPython の例です。

# require: pip install launchdarkly-server-sdk
import ldclient
from ldclient.config import Config

if __name__ == "__main__":
    ldclient.set_config(Config('***SDK Key here***'))
    ld_client = ldclient.get()

    try:
        launch_darkly_user = {
                "key": 'FE229D77',
                "firstName": 'Taro',
                "lastName": 'Yamada',
                "custom": {
                    "favorites": '🌮, 🍛'
                }
            }
        ld_client.identify(launch_darkly_user)
    finally:
        ld_client.close()

このコードを実行すると、以下の画像のようにダッシュボードの機能を使えるようになります。

f:id:miso_soup3:20210813162746p:plain
ユーザー一覧に表示されるようになっています
f:id:miso_soup3:20210813162810p:plain
ダッシュボードでは、複数のフラグを一括で管理できます
f:id:miso_soup3:20210813162825p:plain
インデックスされれば、フラグのページにてオートコンプリートが表示されます

このユーザー情報は、30日間フラグが評価されないと、ユーザーページから削除され、ダッシュボードは使えなくなります。削除された後にフラグの評価が行われたり、上記のコードが実行されれば、再び表示されるようになります。もちろん、フラグの設定状態が失われるわけではありません。

References

Identify creates or updates users in LaunchDarkly, which makes them available for targeting and autocomplete on the dashboard. Identifying and changing users


The Users page shows only cached user information. Users live in the dashboard for 30 days from creation. If a user does not evaluate a feature flag within 30 days, they age out of the system and their information no longer appears in the Users dashboard. The Users dashboard

Jasmine は async/await と done() による callback の混合をサポートしない

Jasmine (version 3.8 で確認)では、以下のコードような、async(async/await の async)と done() による callback を混合した書き方はサポートしなくなったようです。

it("test", async (done) => {
    await somethingPromise(1000);
    done();
});

実際にこのテストを実行すると、成功扱いになりますが、以下のように警告が出力されます。

DEPRECATION: An asynchronous before/it/after function was defined with the async keyword but also took a done callback. This is not supported and will stop working in the future. Either remove the done callback (recommended) or remove the async keyword. (in spec: test test)

GitHub にて、該当のコミット者によるコメントがありました。

Jasmine doesn't support mixing callback-style and async/await in a single function.

Expectation when using both done and async functions? · Issue #1731 · jasmine/jasmine · GitHub

※サンプルのコードでは、async と done() を混合しなければいけない理由が不明かと思いますが、良いサンプルが思いつけませんでした。

なぜか

上記の GitHub のコメントを参考に、なぜこうなったのかは以下のように理解しました。

Jasmine は、2.7 から async/await をサポートしています。

async/await is supported by Jasmine 2.7 and later.

Asynchronous work

それまでは done() によって非同期のテストが書かれており、必然的に done() が実行されたかどうかでテストの完了を判断していたと思われます。

しかし、async/await をサポートすることによって、it("test", async (done) => {} のようなテストコードの場合、Promise の完了をもってテスト完了と判断するのか、done() の実行をもってテスト完了と判断するのか、コードの読み手は混乱することになると思います。仮に挙動を定めたとしても Jasmine はそれを信頼すべき挙動とは断言したくなかったのでしょうか? そのために、混合をサポートせず冒頭のような警告が出力されるようになったのかと思います。

どうすればよいか

混合を避けて、done() だけで書くか、async/await だけで書くか、どちらかにコードを変更します。このコードは、こちら Continued support for async tests with done callbacks · Issue #1893 · jasmine/jasmine · GitHub を参考にしました。

done() だけを使う場合:

it("test2", (done) => {
    (async () => {
        await somethingPromise(1000);
        await somethingPromise(1000);
        done();
    })();
});

async/await だけを使う場合:

it("test3", async () => {
    await somethingPromise(1000);
    await somethingPromise(1000);
    await expectAsync(somethingPromise(1000)).toBeResolved();
    await expectAsync(somethingErrorPromise(1000)).toBeRejected();
});

このとき、toBeRejectedWith() toBeRejectedWithError() などのメソッドも役に立ちそうです。

今回のコード: Jasmine tests · GitHub