Upstash RedisでNext.jsに機能フラグを実装し、安全で柔軟なリリースを実現する方法
ソフトウェアのアップデートは避けて通れません。バグの修正、新機能の追加、そしてセキュリティや信頼性、速度の向上のための改善は、継続的な開発の中で常に求められます。
しかし、新機能や変更をデプロイと密接に結びつけるのは必ずしも得策ではありません。定期的なデプロイスケジュールに沿ってリリースしても、マーケティングチームがまだ新機能の発表準備を整えていないケースは少なくありません。変更がコードにハードコードされていれば、機能の有効化・無効化のたびに開発者の力を借りることになってしまいます。
機能フラグ(フィーチャートグル)は、こうした変更をデプロイから切り離すための仕組みです。実装した機能をif文の背後に隠しておき、変数がfalseの間は従来の動作を、trueになると新しい動作を使うようにします。この変数の値をデータベースから取得する設計にすれば、マーケティングチームでもコードを一切触ることなく、機能のオン・オフを切り替えられるようになります。
Upstash Redis®はまさにその用途に適したデータベースです。シンプルなキーバリューストアであり、機能フラグの保存先として最適です。非常に高速なので、アプリケーション内で複数のフラグを確認しても、レイテンシへの影響はごくわずかです。
本チュートリアルでは、Next.jsアプリ向けのシンプルな機能フラグ機構の構築方法を解説します。ホスティングにはVercelを、ストレージにはUpstash Redis®を使用します。
前提条件
GitHubアカウント、Vercelアカウント、Upstashアカウントが必要です。
また、NPMを使用するため、最新版のNode.jsがインストールされている必要があります。
Next.jsプロジェクトの初期化
最初のステップは、新しいNext.jsプロジェクトの作成です。以下のコマンドで作成できます。
$ npx create-next-app upstash-next-feature-flags
Upstash Redis®接続の作成
次に、Next.jsアプリをUpstash Redis®データベースに接続します。そのために、@upstash/redisパッケージをインストールし、簡単なラッパーを作成します。
$ npm i @upstash/redis
upstash-next-feature-flags/lib/featureFlags.jsというファイルを作成し、以下のコードを記述します。
import { Redis } from "@upstash/redis";
const { UPSTASH_TOKEN, UPSTASH_URL } = process.env;
const redis = new Redis({
token: UPSTASH_TOKEN,
url: UPSTASH_URL,
});
export async function flagIsActive(flagName) {
const flag = await redis.get(flagName);
return Boolean(flag);
}
API認証情報は環境変数から取得します。設定方法は後ほど説明します。flagIsActive関数はRedis®に問い合わせを行い、返された値をboolean型に変換します。フラグはRedisに数値として保存するため、この変換が必要になります。
APIルートの作成
続いて、2つの異なる実装を持つAPIルートを作成します。機能フラグを使って両者を切り替えます。
upstash-next-feature-flags/pages/api/sort-numbers.jsというファイルを作成し、以下のコードを記述します。
import { flagIsActive } from "../../lib/featureFlags";
export default async function handler(request, response) {
let sort = bucketSort;
const newSortingAlgorithm = await flagIsActive("newSortingAlgorithm");
if (newSortingAlgorithm) sort = selectionSort;
const { numbers } = request.body;
const sorted = sort(numbers);
response.status(200).json({
numbers: sorted,
newSortingAlgorithm,
});
}
// old sorting algorithm
const bucketSort = (arr, size = 5) => {
const min = Math.min(...arr);
const max = Math.max(...arr);
const buckets = Array.from(
{ length: Math.floor((max - min) / size) + 1 },
() => [],
);
arr.forEach((val) => {
buckets[Math.floor((val - min) / size)].push(val);
});
return buckets.reduce((acc, b) => [...acc, ...b.sort((a, b) => a - b)], []);
};
// new sorting algorithm
const selectionSort = (arr) => {
const a = [...arr];
for (let i = 0; i < a.length; i++) {
const min = a
.slice(i + 1)
.reduce((acc, val, j) => (val < a[acc] ? j + i + 1 : acc), i);
if (min !== i) [a[i], a[min]] = [a[min], a[i]];
}
return a;
};
このAPIルートはシンプルな数値ソーターです。未ソートの数値配列を受け取り、2つのソートアルゴリズムのいずれかを使って並べ替えます。
これらのソートアルゴリズムは、アプリケーションで「切り替え」たい任意の変更を表すサンプルと考えてください。両方のコードを用意しておき、Redisの値を変更することでflagIsActive関数経由で切り替えます。
flagIsActive関数を呼び出す際には、確認したいフラグ名を渡します。Redisでフラグが1に設定されていればtrueを返し、そうでなければfalseを返します。
ソート処理の後、APIルートはソート済みの配列をJSONとして返します。
GitHubへのプッシュ
すべての実装が完了したら、Vercelのデプロイサービスからアクセスできるよう、プロジェクトをGitHubのリポジトリにプッシュします。リポジトリの作成方法については、GitHubの公式ドキュメントを参照してください。空のリポジトリを作成すると、既存プロジェクトとの連携手順が自動的に表示されます。
Upstash Redis®データベースの作成
Upstashコンソールで新しいデータベースを作成できます。図1は、本チュートリアルに適した設定例です。

図1のとおり、無料枠のデータベースが提供されているため、このチュートリアルでは費用は一切かかりません。
後ほどデータベースの認証情報を取得する必要があるため、Upstashコンソールのブラウザタブは開いたままにしておきましょう。
GitHubリポジトリとVercelの連携
GitHubアカウントでVercelにログインしていれば、GitHubリポジトリの追加は数クリックで完了します。図2はVercelダッシュボードの左上部です。「Add New…」をクリックして「Project」を選択します。

「Continue with GitHub」を選択し、前の手順で作成したリポジトリに対応する「Import」ボタンをクリックします。

最後にプロジェクト設定画面が表示されるので、ここで環境変数を入力します。それ以外の設定はデフォルトのままで問題ありません。図4は環境変数の入力箇所を示したものです。

変数名はUPSTASH_TOKENとUPSTASH_URLで、値は先ほどデータベースを作成したUpstashコンソールで確認できます。図5は必要な値をコピーするためのボタンの位置を示したものです。

大きな「Deploy」ボタンを押すと、VercelがGitHubリポジトリをクローンし、自社インフラ上へデプロイします。
Redisによる実装の切り替え
これでAPIエンドポイントを呼び出せるようになり、Redisに値を設定するだけで実装を切り替えられます。最も手軽な方法は、UpstashコンソールのRedis CLIを使うことです。
図6はCLIの場所と、値を設定するために実行するコマンドを示したものです。
set newSortingAlgorithm 1
newSortingAlgorithmキーを削除するか0に設定すると、フラグはfalseに戻り、APIルートは旧アルゴリズムを使用するようになります。
APIルートの利用
最後に残っているのは、APIルートの実際の使用です。POSTリクエストでJSONオブジェクトを送信する必要があります。cURLを使うのが手軽でしょう。
以下のコマンドでJSONオブジェクトを送信できます。
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"numbers":[1, 100, 10, 1000, 100000, 10000]}' \
API_ROUTE_URL
API_ROUTE_URLはVercelで確認してください。図7のように、Vercelダッシュボードのプロジェクトページに「Domains」セクションが表示されているはずです。

レスポンスとしては、ソート済みのnumbersと、どちらのアルゴリズムが使われたかを示すnewSortingAlgorithmフィールドを含むJSONオブジェクトが返されます。
まとめ
機能フラグは、デプロイと機能リリースを切り離すための優れた手法です。ハードコードされた変更を、データベース上の単純な値の更新に置き換えることで、チームに柔軟性をもたらし、非エンジニアにも機能の制御権限を与えられます。
Upstash Redisのような高速なデータベースを活用すれば、パフォーマンスをほとんど犠牲にすることなく、アプリケーションに機能フラグパターンを導入できます。Upstash Redisはサブ秒レベルの高速アクセスを実現し、必要に応じてFaaSの近くに配置することも可能です。さらに従量課金制なので、使っていないリソースに対して支払うことはありません。
-
Azure Cache for Redis Enterpriseで「アクティブ・アクティブ地理分散」が一般提供開始
Azure Cache for RedisのEnterpriseおよびEnterprise Flash階層において、Redisによる「アクティブ・アクティブ地理分散(Active-Active Geo-Distribution)」の一般提供が開始されたことをお知らせします。これにより、Azure Cache for Redisのお客様は、異なるAzureリージョンに最大5つのEnterprise階層キャッシュデータベースインスタンスを配置し、コンフリクトフリーレプリケーションデータ型(CRDT)を活用したアクティブなgeoレプリケーションキャッシュを構築できるようになりました。Enterpri
-
AWS LambdaとRedis Enterprise Cloudで実現するサーバーレス開発の徹底解説
本記事では、AWS LambdaとRedis Enterprise Cloudを連携させる方法を詳しく解説します。サンプルとして映画データベースアプリケーションを題材に、Node.js製とPython製の2つのLambda関数を構築・デプロイする流れを学べます。これらの関数はRedisデータベースとやり取りし、データの挿入・更新・削除・検索(クエリ)を行います。アプリケーションでは、高度な検索機能を提供するRediSearch APIを採用しています。サーバーレス(AWS Lambda)は、マイクロサービスアーキテクチャへの移行トレンドとも相性が抜群です。開発者はビジネス上の「サービス」を小さ