質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

3回答

591閲覧

node.jsのclusterモジュールで、子プロセスからMySQLに接続する方法

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2018/06/05 09:17

編集2018/06/05 11:45

node.js v9.11.1
cluster: 0.7.7

node.jsのclusterモジュールを使っているのですが、親プロセスからは問題なくMySQLに接続できるのですが、子プロセスからは繋がりません。

どうやって繋げるのでしょうか?

下の例は親のMySQLの実行結果を子に渡して、子はその値を元にMySQLを実行する、というものです。

子にデータは問題なく渡っているのですが、その先が詰まってしまって困っています。
よろしくお願い致します。

javascript

1'use strict'; 2 3const mysql = require('mysql2/promise'); 4const cluster = require('cluster'); 5const CPUs = require('os').cpus().length; 6 7// MySQL接続 8const connect = () => { 9 const connection = mysql.createConnection({ 10 host: 'localhost', 11 user: 'root', 12 password: '', 13 database: 'test' 14 }); 15 return connection; 16} 17 18// 親プロセス 19const master = async () => { 20 // MySQL接続 21 const conn = await connect().catch((err) => { 22 console.log(err); 23 }); 24 25 // workerプロセスを作成 26 for (let i = 0; i < CPUs; i++) { 27 const worker = cluster.fork(); 28 } 29 30 // MySQL実行 31 let row; 32 const sql = `SELECT id FROM hoge LIMIT 1`; 33 try { 34 [row] = await conn.query(sql); 35 } catch (err) { 36 console.log(err); 37 } 38 39 // 実行結果を子プロセスに渡す 40 try { 41 cluster.on('online', (worker) => { 42 if (row[0]) worker.send(row[0].id); 43 }); 44 } catch (err) { 45 console.log(err); 46 } 47} 48 49// 子プロセス 50const child = async () => { 51 // MySQL接続 ←ここが動いていない 52 const conn = await connect().catch((err) => { 53 console.log(err); 54 }); 55 56 // 親から値を受け取る 57 process.on('message', async (msg) => { 58 // MySQL実行 59 let row2; 60 const sql2 = `SELECT data FROM fuga WHERE id = ? LIMIT 1`; 61 try { 62 [row2] = await conn.query(sql2, [msg]); 63 } catch (err) { 64 console.log(err); 65 } 66 67 console.log(row2[0].data); 68 }); 69} 70 71if (cluster.isMaster) { 72 master(); 73} else { 74 child(); 75}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

2つぐらい問題を見つけました。

###(A)カラム名のtypo

若干弄りながらテストしてる段階で

TypeError [ERR_MISSING_ARGS]: The "message" argument must be specified

とメッセージが出たので、よくよくコードを見たら親プロセスの方の最初のSQLでidカラムを問い合わせているのに、結果セットを参照している箇所がsend(row[0].queue_id)となってることに気づきました・・・
これだとsendにundefinedが渡されることになり「何も指定してない」と見做されこのメッセージが出るんじゃないでしょうか。質問者さんんが実行したときはこのメッセージが出てませんでしたか?

###(B)on('message', ...)
こちらの問題ははっきりこうと言えませんが・・・

(A)を対策して動かしてみると.on('online', ...)が先に動いてその後子供プロセスが動き出しDBへの接続まで進み、その後.on('message', ...)のハンドラーが起動してないように見えました。

一瞬「子供プロセスがmessageハンドラーを登録する前にsendするとメッセージが失われのだろうか?」と思い、

(B1) onlineになってから500msecぐらい時間をおいてsendする

とすると成功したのですが、ハンドラーが登録されてからでないとsendできないは「間違いのような気がした」ので、(B1)の代わりに

(B2) 子供プロセス起動直後にmysqlの接続をせずにmessage受信後に接続する

とするとそちらでも期待通りに動くようでした。なぜ(B2)をやってみたかというと...

mysqlの接続をawaitを用いて接続待ちしている際に親プロセスから既にmessageイベントがキューイングされているはずなのだけどそのハンドラーを登録する前にEmitterを使うような非同期処理をやってしまうとだめなのでは・・・というふうに想像したのです。ちゃんと仕様を調べてないのでこれは単なる勘です。

すみませんが、本当のところはわかってません。どなたか詳しい方がコメントくださると嬉しいのですが・・・(スミマセン)

投稿2018/06/05 10:50

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/06/05 11:48

ありがとうございます。 (A)は単なるケアレスミスだったので修正しました。例ではなくて元のソースの一部が残っていたのでスルーでお願い致します。
KSwordOfHaste

2018/06/05 11:57 編集

(A)の方ー>了解です。 (B)の方が自分は気持ち悪いです。回答してはみたもののとんでもない間違いを犯している予感がします・・・
guest

0

ベストアンサー

解決しました。
cluster.on('online')が今回期待通りの動きをしてくれなかったのがそもそもの原因でした。

自分はclusterモジュールでの親子間の会話が、どちらから始まるのかがわからなかったのですが、今回のケースだと子から始めるとうまくいくとわかりました。

onlineイベントハンドラは単純に子プロセスに繋がれば親に教えてくれるだけなので、子へメッセージを渡してくれません。

そこで子が親にどつかれて何か返事をすれば、親プロセスが子にメッセージを渡すという方法に変えました。

下のようなTABLEがあったとします。

MySQL

1MariaDB [test]> select * from hoge; 2+----+-----------------+ 3| id | fuga | 4+----+-----------------+ 5| 1 | 福沢諭吉 | 6| 2 | 夏目漱石 | 7| 3 | 野口英世 | 8| 4 | 新渡戸稲造 | 9| 5 | 樋口一葉 | 10+----+-----------------+

長くなるのでtry catchは省略しました。

javascript

1'use strict'; 2 3const mysql = require('mysql2/promise'); 4const cluster = require('cluster'); 5const CPUs = require('os').cpus().length; 6 7// MySQL接続 8const mysqlConf = { 9 host: 'localhost', 10 user: 'root', 11 password: '', 12 database: 'test', 13}; 14 15// 親プロセス 16const master = (conn) => { 17 // 子からメッセージを受け取ったらMySQL接続 18 cluster.on('message', async (worker, msg) => { 19 if (msg == '__REPLY__') { 20 const sql = `SELECT fuga FROM hoge WHERE id = 2`; 21 const [row] = await conn.query(sql); 22 await worker.send(row[0].fuga); // 子に結果を渡す 23 } 24 }); 25 26 // CPUの数だけフォークする 27 for (let i = 0; i < CPUs; i++) { 28 cluster.fork(); 29 }; 30}; 31 32// 子プロセス 33const child = async (conn) => { 34 // まず子から親に話しかける 35 await process.send('__REPLY__'); 36 37 // 親から返事を受け取ったらMySQL接続 38 process.on('message', async (msg) => { 39 const result = `SELECT id, fuga FROM hoge WHERE fuga = ?`; 40 const [rowResult] = await conn.query(result, [msg]); 41 console.log(rowResult[0].id, rowResult[0].fuga); 42 }); 43}; 44 45const main = async () => { 46 const conn = await mysql.createConnection(mysqlConf); 47 if (cluster.isMaster) master(conn); 48 else child(conn); 49}; 50 51main();

実行結果

text

12 '夏目漱石' 22 '夏目漱石' 32 '夏目漱石'

上記コードは接続を切っていないので、子プロセスが処理をすべて終えたら接続を切る必要があると思います。

投稿2018/06/16 11:44

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

>(B2) 子供プロセス起動直後にmysqlの接続をせずにmessage受信後に接続する
の方法で一応確認できました。

ただいろいろ試したのですが、私自身も納得のいかない部分もあり、未解決ということにさせて頂きます。

修正した部分は以下です。

javascript

1const child = async () => { 2 // 親から値を受け取る 3 process.on('message', async (msg) => { 4 // MySQL接続 ここから 5 const conn = await connect().catch((err) => { 6 console.log(err); 7 }); // ここまでをprocess.onの下に移動 8 9 // MySQL実行 10 let row2; 11 const sql2 = `SELECT data FROM fuga WHERE id = ? LIMIT 1`; 12 . 13 . 14 . 15(略)

投稿2018/06/06 06:25

編集2018/06/06 06:28
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問