質問: socketio.listen(server); io.on('connection', function (socket) { socket.on('chat message', function (data) { // MySQL データベースへ送信されたメッセージを保存 connection.query('INSERT INTO `message` (text) VALUES (?)', [data], function (error, results, fields) { if (error) console.log(error); }); }); }); ```
回答: 実際には懸念が一つだけありますが、基本的には大丈夫でしょう。 > > 例えばユーザーからほぼ同時に100件などのメッセージがきた場合に接合性のあるデータ保存が可能なのか > > > これは間違いなく大丈夫です。 何故ならNode.jsはシングルスレッドであり、なんちゃって並列処理だからです。 ざっと説明しておきますと、Node.jsはイベントループという概念で内部は動いてます。 `node index.js`等と実行された時に、Node.jsは対象のソースコードに書かれている処理を全て処理してしまいます。 全て処理し終えたNode.jsはイベントループという巡回を行うだけのモードに移行します。 `socket.on('chat message', fn)`はイベント登録です。 ユーザーからのメッセージを受け取った時点でイベントの発火条件がクリアされて関数`fn`が発火準備状態になります。 その後、イベントループで順番待ちになっている`fn`を1個だけ掴んで処理し始めます。 1個の順番待ちをこなしたら、次の順番待ちの`fn`を処理し始めます。 このように目にも留まらぬ速さで処理しまくるイベントループ君ですが、一度に処理出来るのは常に1個だけです。 そして`io.on('connection', fn)`という風に各ユーザの情報は関数スコープによって閉じられていますので、 大量にメッセージを受け付けたとしてもスコープが別なのでAユーザの発言とBユーザの発言が混ざるという事もありません。 それを証拠に下記のように無限ループを作って後続の処理が行われないようにしておくと、 次のユーザがメッセージを送信出来なくなるはずです。 ``` io.on('connection', function (socket) { socket.on('chat message', function (data) { console.log(data); while(true) var i = 0; }); }); ``` おまけ: 懸念に関して これは単純に私がsocket.ioを利用した事が無いから来る疑問点です。 TCPで受信出来るパケット数は限られている為、 長文を受け取ると1つのメッセージを2段階に分けて受信する可能性があります。 例えば平成の菅原道真がチャットに出現して、「いろはにほへと......」と長文のポエムを送信したとしましょう。 「いろはn」「iほへと」みたいな文字の途中で切られてしまった場合、 UTF-8の日本語は3バイトなのでバイト列の途中でぶった切られ、文字化けの原因になります。 更に文字列が区切られるので2メッセージ扱いとなり、MySQLには2レコードが挿入されます。 この場合、クライアント側はチャット内容のテキストメッセージ本体を送信するのではなく、一度JSON.stringifyで文字列1個のJSONに変換すると良いかもしれません。 そうすればサーバ側でJSON.parseで評価出来ずエラー落ちした場合、 一度文字列を退避させておいて、後続のメッセージと一緒にくっつけるという手が使えます。 まずは一度長文の文字列を放り込んで確認してみてください。