カエルの人 logo
  • About 
  • Works 
  • Blog 
  • Tags 
  • Privacy 
  • Contact 

  •  Language   
    • 日本語
    • English
  •    テーマ切り替え
    •   ライト
    •   ダーク
    •   自動
  •  
    •   ライト
    •   ダーク
    •   自動
  1. ホーム
  2. ブログ
  3. Redis が無限に再接続し続けた原因はたった1文字のタイプミスでした

Redis が無限に再接続し続けた原因はたった1文字のタイプミスでした

投稿: 2023年1月8日  (最終更新: 2023年12月1日) • 4 分 で読了 • 1,680 語
プログラミング
 
Redis
 
トラブル対処
 
プログラミング
 
Redis
 
トラブル対処
 
共有:
カエルの人
リンク をクリップボードにコピーしました

目次
 

  • 問題コード
  • redis:// じゃなくて rediss:// じゃね?
  • 開発環境と本番環境で切り替える
  • 余談と愚痴

Redis が無限に再接続し続けた原因はたった1文字のタイプミスでした

現在作っている学校用の Node.js (Express) アプリで Upstash の Redis を使おうとしたところ、切断→再接続を超高速で無限に繰り返す謎の不具合に悩まされたのですが、結果あっさり解決してしまった話です。

※この記事では本来は「URI」と表記するものであっても、わかりやすさを重視し「URL」に統一して表記しています。予めご了承下さい。

問題コード  

では早速、問題になったコードです。

ライブラリは ioredis と connect-redis を使って書きました。

また、以下のコードは Redis の部分のみを抜粋しているので、実際に動かす場合はその他の必要なコードを追加する必要があります。

const Redis = require('ioredis');
const connectRedis = require('connect-redis');

// Redis
const RedisStore = connectRedis(session);
const redisClient = new Redis(`redis://${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_ENDPOINT}:${process.env.REDIS_PORT}`);

redisClient.on('error', e => {
 console.error('Redis error:', e);
});

redisClient.on('connect', () => {
 console.log('Redis connected');
});

redisClient.on('reconnecting', () => {
 console.log('Redis reconnecting');
});

redisClient.on('end', () => {
 console.log('Redis disconnected');
});

このプログラムを実行した結果、

    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
    Redis connected
    Redis reconnecting
        ・
        ・
        ・
    (以下、無限ループ)

こんな感じで、切断と再接続を超高速で無限に繰り返すという謎の挙動になってしまいました。

数日間悩み、しまいには Upstash の不備なんじゃないかとも思いながらも、ドキュメントを眺めていたらふと気が付きました。

redis:// じゃなくて rediss:// じゃね?  

先程のコードの6行目

const redisClient = new Redis(`redis://${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_ENDPOINT}:${process.env.REDIS_PORT}`);

の redis:// の部分を rediss:// と、s を1つ多くしたらすんなり動いてしまいました。

そういえばデータベースを作るときに SSL/TLS を有効にした気が…

TLS (SSL) が有効になっている

ちゃんと有効になってました。

ウェブサイトでも SSL/TLS が有効なページは、URL が http:// ではなく https:// と、s が1個多くついた文字列で始まるように、Redis も、SSL/TLS が有効だと rediss:// と s が1個多くつくようです。

先程のコードで指定した Redis の URL は redis:// から始まっており、SSL/TLS が有効になっていませんでした。

だから、Upstash 側で弾かれていたわけです。

以上のことをまとめると、正しいコードは以下のようになります。

const Redis = require('ioredis');
const connectRedis = require('connect-redis');

// Redis
const RedisStore = connectRedis(session);
const redisClient = new Redis(`rediss://${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_ENDPOINT}:${process.env.REDIS_PORT}`);

redisClient.on('error', e => {
 console.error('Redis error:', e);
});

redisClient.on('connect', () => {
 console.log('Redis connected');
});

redisClient.on('reconnecting', () => {
 console.log('Redis reconnecting');
});

redisClient.on('end', () => {
 console.log('Redis disconnected');
});

6行目で指定している URL を、redis:// ではなく rediss:// で始めるようにしました。

開発環境と本番環境で切り替える  

ただ、開発環境に用意した Redis は SSL/TLS に対応していないことが多いと思います。

その場合、以下のようにして開発環境と本番環境で SSL/TLS の有効・無効を切り替えるといい感じになります。

const Redis = require('ioredis');
const connectRedis = require('connect-redis');

// Redis
const RedisStore = connectRedis(session);
const redisClient = new Redis(`${app.get('env') === 'development' ? 'redis://' : 'rediss://'}${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_ENDPOINT}:${process.env.REDIS_PORT}`);

redisClient.on('error', e => {
 console.error('Redis error:', e);
});

redisClient.on('connect', () => {
 console.log('Redis connected');
});

redisClient.on('reconnecting', () => {
 console.log('Redis reconnecting');
});

redisClient.on('end', () => {
 console.log('Redis disconnected');
});

6行目の

app.get('env') === 'development' ? 'redis://' : 'rediss://'

の部分がポイントです。

app.get('env') で、環境変数 NODE_ENV の値を読み取り、開発環境か本番環境かを判定します。

NODE_ENV が development、すなわち開発環境であれば redis:// を、そうでなければ rediss:// を使うという動作になります。

以上、数日間悩み続けたトラブルがたった1文字加えるだけで解決してしまった話でした。

この記事が、同じトラブルに遭遇している方の一助になれば幸いです。

余談と愚痴  

誤ったコードで再接続を無限に繰り返した結果、昨日のリクエスト数がすごいことになりました。

リクエスト数の推移; 昨日3931、本日87

それほど長くは動かしていないのですが、ループの速度がものすごく、ログが残像しか見えない程の速度で流れていたのでこのくらい行っちゃうよなぁという感じです。

で、なぜこんなに悩まされたのかというと、Upstash の管理画面からコピペできる URL が SSL/TLS 非対応のもの (redis:// から始まるもの) だったんですよね。

もしかして CLI からアクセスする場合は rediss:// ではなく redis:// を使う必要があるんでしょうかね?

そこまで調べきれていないのでなんとも言えませんが、ちょっと不親切だなと思いました。

ちなみに、Upstash さんはご親切に各言語・ライブラリでのコードの書き方の例を表示してくれるのですが、そちらはちゃんと SSL/TLS 対応の URL になっていました。

うん、そっちをよく確認しなかった僕の方が悪い。

 【Google Pixel】外出したらマナーモードを自動でオンにする
一言日記(2023年1月) 

関連記事

Colaboratory を楽しくする設定

2022年11月26日 • 1 分 で読了

Colaboratory を楽しくする設定

Colaboratory を使っていたら面白そうな設定を見つけたので紹介します。最近は学校で Colaboratory を使うこともあるようですが、この設定を有効にすれば授業を200%楽しめ...

ローカリゼーションの難しさ

2022年9月25日 • 4 分 で読了

ローカリゼーションの難しさ

「ローカリゼーション」という言葉を知っていますか?ローカリゼーションの意味や目的は多種多様ですが、ここでは「外国のソフトウェアをその国の言語...

三項演算子が便利すぎて感動した

2021年10月20日 • 2 分 で読了

三項演算子が便利すぎて感動した

数ヶ月前、三項演算子に出会って感動したので、まだこの感動を味わっていない方向けに記事を書きました。 三項演算子の便利さ   このような処理をしよう...

Glitch のプロジェクトを削除する方法を調べてみた!

2021年10月6日 • 2 分 で読了

Glitch のプロジェクトを削除する方法を調べてみた!

node.js をブラウザ上で使える Glitch を使っていて、プロジェクトの削除方法が気になったので調べてみました。 結論   結論から言うと、現時点では Glitch でプロジェクト...

学生は無料で GitHub Pro が使える?特典や申請方法などを解説!

2021年9月18日 • 4 分 で読了

学生は無料で GitHub Pro が使える?特典や申請方法などを解説!

GitHub がますます好きになっちゃう

GitHub の草、17週連続フルコンボ達成!

2021年9月18日 • 1 分 で読了

GitHub の草、17週連続フルコンボ達成!

この度、GitHub の草で、17週連続フルコンボを達成しましたことをご報告いたします。 「GitHub の草」というのは、GitHub 農場で育て...

目次
  • 問題コード
  • redis:// じゃなくて rediss:// じゃね?
  • 開発環境と本番環境で切り替える
  • 余談と愚痴
Copyright © 2024 カエルの人 All rights reserved. Powered by Hinode  .
カエルの人
コード をクリップボードにコピーしました