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

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

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

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

2回答

722閲覧

Linuxサーバで、CGIからのバックグラウンドプロセス開始方法

cellostar

総合スコア11

CGI

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

0クリップ

投稿2022/08/28 03:55

前提

エックスサーバー(CentOS)上に次のようなものを実装したい。
・サーバー上で、常時pythonのプログラムを動かす
・そのプログラムを、筆者と他1名で共同開発
・そのために、コントロールページを作り、そこからプログラムの開始・停止・ソース編集などができるようにする

その第一段階として、コントロールページからpythonプログラムのバックグラウンド実行を試みています。

ソースコード

・コントロールページ

HTML

1<html> 2<body> 3<form id="mainForm" action="run.rb" method="POST"> 4 <button>コード実行</button> 5</form> 6</body> 7</html>

・run.rb(HTMLより呼び出し)

Ruby

1#!/usr/bin/ruby 2 3puts "Content-Type: text/plain\n" 4puts "Access-Control-Allow-Methods: GET,POST\n" 5puts "Access-Control-Allow-Origin: *\n\n" 6 7# 方法1: 8spawn('python /home/xxx/xxx.xsrv.jp/script/test.py') 9 10# 方法2: 11System('nohup /home/xxx/xxx.xsrv.jp/script/test.py &')

・test.py(現段階では、一定間隔でlogファイルにhello worldを出すのみ)

Python

1import time 2import datetime 3import sys 4import os 5 6print("プログラム開始") 7print(sys.version) 8 9f = open(os.path.dirname(__file__) + '/out.log', 'w') 10f.write(datetime.datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')) 11f.write("\n処理開始\n") 12f.close() 13 14while True: 15 f = open(os.path.dirname(__file__) + '/out.log', 'a') 16 f.write(datetime.datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')) 17 f.write("\nhello world!\n") 18 f.close() 19 time.sleep(2) 20 21print("プログラム終了")

現状・問題点

サーバーにSSH接続し、ターミナルからrbファイルを実行すると、期待する動作になります。
(=バックグラウンドでpythonが動き続ける)
が、コントロールページからCGiを実行すると、
方法1の場合:画面に何も表示されず、プロセスもない(=実行されない)
方法2の場合:ページの読み込みが終わらない
という結果になってしまいます。
方法2について補足すると、コマンドを

nohup dir &

に変えると、ページ上にdirの結果が表示されることを確認しています。
つまり、nohupにしているにもかかわらず、プログラムの終了を待ち、その結果を出そうとしています。
(ページには以下の文言が出るだけで、コマンドの結果は出ない  というのを期待していたのですが。)

nohup: 出力を `nohup.out' に追記します

まとめ

CGIから、バックグラウンドプロセスを起動する方法をご教授いただきたいです。
Linuxなどについて殆ど知識がないので、おかしなことをしているのかもしれませんが、アドバイス頂けますと幸いです。- リスト

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

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

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

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

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

guest

回答2

0

Pythonプロセスをデーモン化する。

Ruby

1# リダイレクトは面倒なので、シェル側でやっておく 2spawn('python /home/xxx/xxx.xsrv.jp/script/test.py </dev/null >/dev/null 2>/dev/null')

制御端末を切り離してforkして子プロセス側で実行。

Python

1import os 2import sys 3 4os.setsid() 5if os.fork(): sys.exit() 6 7以下処理

投稿2022/08/28 16:10

otn

総合スコア84499

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

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

cellostar

2022/08/29 01:24

ご回答、ありがとうございます。 調べる中でforkも見つけたのですが、2回しないといけない(?)など記載がありよく理解できなかったので敬遠していました。 このように、スマートに表現できるのですね。 素人目には、if os.fork() とすると子プロセスがまたforkして無限ループ?などと思ってしまうのですが、子プロセスはtest.pyを頭から実行するのではなく親と同じところから実行する、ということなのでしょうか。 とすれば、 ”成功した場合には、親プロセスには子プロセスのIDが返り子プロセスには0が返る” とありますので、親はif true となりexit、子はif falseとなり続行 という感じなのかなと、納得できます。 ありがとうございました。また機会があれば、よろしくお願いいたします。
otn

2022/08/29 10:08

> 子プロセスはtest.pyを頭から実行するのではなく親と同じところから実行する、ということなのでしょうか。 そうですね。「フォーク」というのは「枝分かれする」というような意味で、そこから親も子も継続します。 > 調べる中でforkも見つけたのですが、2回しないといけない(?)など記載がありよく理解できなかったので敬遠していました。 はい。forkは2回必要ですが、今回は、Ruby側のspawnが1回目のforkになっているので、Python側では1回で十分です。もちろん2回やっても良いですし、10回やってもいいです。
guest

0

ベストアンサー

方法2の場合:ページの読み込みが終わらない

おそらくhttpサーバがstdoutのcloseを待つためです。
子プロセス(test.py)の最初に stdoutをcloseしてみてください。

投稿2022/08/28 04:28

sigsegv

総合スコア895

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

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

cellostar

2022/08/28 06:46

ご回答、ありがとうございます。 test.pyに sys.stdout.close() を追加しただけでは、解決しませんでした。(読み込み終わらないままでした) ただ、仰ったことをヒントに色々と試行錯誤したところ、以下の方法で意図する動作ができました。 ・python呼び出し用のbashスクリプトを用意しておく nohup python /home/xxx/xxx.xsrv.jp/script/test.py & ・RubyのCGIから、出力を一切受け取らずにbashスクリプトを実行 system("bash /home/xxx/xxx.xsrv.jp/script/run.sh > /dev/null 2>&1") 外部プログラムから何も出力させないということが、鍵だったようです。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問