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

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

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

解決済

phpのタイムアウト処理を導入したい

honda_ta
honda_ta

総合スコア10

1回答

0評価

0クリップ

263閲覧

投稿2022/05/03 13:54

編集2022/05/08 11:36

事情説明

WordPressで作成した「サイトA」のRSSフィードを使用して
「サイトB」にサイトAの更新情報をコンテンツの一部として表示させているのですが、
WordPress側でメンテナンスや障害が発生すると、サイトBで処理待ちリクエストが増え、サイトBまで落ちてしまいます。

ちなみにサイトAはエックスサーバーを使用しており、そちらで少し前に大規模な障害が発生した際には、サイトBまで表示ができなくなっていました。

この問題を回避するためには、サイトAの更新情報をサイトBにiframeで読み込むという手段もあるのですが、これはあまり使いたくないので
タイムアウト処理を導入して一定時間が経ってもサイトAの更新情報を取得できない場合は、
その部分だけ「表示できません」とするなど、処理を分けたいと考えています。

ちなみに、サイトAの更新情報取得には「rss-php」というライブラリを使用しています。

https://kana-lier.com/web/php_rssfeed/

これをカスタマイズしてタイムアウト処理を追加する方法を探しています。

試した事

※どのようにタイムアウト処理を実装するかを考察するためのデモです。 ■test.php <?php //タイムスタンプをマイクロ秒単位で取得 $start = microtime(true); //cURLでコンテンツを取得 $url = "test2.php"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 60); $json = curl_exec($ch); curl_close($ch); $result = json_decode($json, true); //もし3秒経過してもコンテンツを取得できなかったら if (microtime(true) - $start > 3) { echo '表示できませんでした'; } else{ echo $json; } ?>
■test2.php <?php //5秒間処理を停止 sleep(5); echo '表示できました'; ?>

発生している問題

上記はデモページのソースです。

test2.phpは、sleep関数で5秒間待ってコンテンツを表示するようにしています。

test.phpではmicrotime 関数を使用して、3秒間待ってコンテンツを取得できなければ別の処理をするようにしています。

test2.phpのコンテンツが表示されるまでに5秒掛かるので、test.phpでは「表示できませんでした」という結果が得られます。

microtime 関数を使用して、一定時間過ぎてもコンテンツが取得できなかった場合は表示を変える事はできました。
ですが、このやり方だと、sleep関数を5秒に設定した場合、5秒待って処理を分けるので、結局、サーバーへの負荷という意味では変わらないのかなと…

タイムアウト処理まで3秒と設定したら、きっちり3秒で条件分岐させたいのですが、どのような手法がありますでしょうか?

phpにはあまり詳しくないので恐縮ですが、何卒よろしくお願いいたします。

※最悪、条件分岐しなくても大丈夫です。サイトB全体が落ちない方法があればお願いします。

追記

実際にサイトBで使用しているRSS取得に関するソースは以下のような感じです。

<?php require_once "Feed.php" ; //rss-phpライブラリを読み込みます $feed = new Feed ; $url = "feed_test.php"; //RSSのURL $rss = $feed->loadRss( $url ) ; $link2 = $rss->link; $num = 20;//表示させたい件数 $i=0; $desW = 0;//詳細の文字数を制限します。制限しないときは0にします。 if ( $desW != 0){ $desW = ($desW*2)+2; } // item毎に処理 foreach( $rss->item as $item ) { if($i>=$num){ } else{ $title = $item->title; $author = $item->author; $targetTime = strtotime($item->pubDate); $date = date('Y年n月j日 H:i', strtotime('-0 hour', $targetTime)); $link = $item->link; $content = $item->children('content', true)->encoded; $description = $item->description; ?> rssを使用したコンテンツ <?php $i++; } } ?> <!--▲RSS取得-->

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

AbeTakashi

2022/05/03 14:23

>このやり方だと、sleep関数を5秒に設定した場合、5秒待って処理を分けるので、 >結局、サーバーへの負荷という意味では変わらないのかなと… 「負荷」という言葉をどういう意味で使ってるか分かりませんが、おそらく変わらないというのはその通りだと思います。「sleepの処理を入れて負荷を減らす」ってのは、この手の話では聞きません(繰り返し処理をゆっくり回して負荷を減らすってのなら聞きますが)。 タイムアウトはApacheやNginx側で設定・調整するのがわりと普通ではないでしょうか?
honda_ta

2022/05/03 14:30

ご回答ありがとうございます。 すみません、sleep関数はmicrotime関数のデモ用で 「サイトBがコンテンツを取得できない状態」を再現したかったので使用しました。 タイムアウト処理とは関係ないです。 >タイムアウトはApacheやNginx側で設定・調整するのがわりと普通ではないでしょうか? こちらその通りだと思いますが、私はサーバーの設定に関与できないので 自分で解決できるのであればその手法を模索したいと思います。 phpでタイムアウト処理できる方法があれば何卒ご教授のほどよろしくお願いいたします。
AbeTakashi

2022/05/03 15:17

基本的にPHPはシングルスレッドで動いてるので、何か処理をしてるときに他の処理を平行ですること(この質問では更新情報を取得中、処理時間を計測して処理を分岐させる)はできませんので、お望みのことをPHPだけでやるのはけっこう難しいと思います。 一応、PHPをマルチスレッドで動かす方法もありますが、質問者さんの環境で使えるかどうかは分かりません。 参考 https://www.sejuku.net/blog/69600
honda_ta

2022/05/03 15:31

なるほど… 「max_execution_time」などは使用できないでしょうか? 参考 https://techacademy.jp/magazine/22837 この際、処理を分岐させなくても、サイトB全体が落ちなければ結果的にはいいのですが… 要は更新情報を表示してるパーツ部分だけがタイムアウトで表示されない…といった形にはできないでしょうか?
AbeTakashi

2022/05/03 15:53

max_execution_time は ini_set を使う方法であればほとんどの環境で使えると思いますが、 単純にプログラムが終了するだけで、処理を分岐をさせることはおそらくできないと思います(頑張って頭をひねればできるかもしれませんが)。 >要は更新情報を表示してるパーツ部分だけがタイムアウトで表示されない…といった形にはできないでしょうか? そのパーツの部分の処理がどうなってるかの詳細が分からないのでなんとも言えませんが、まずはmax_execution_timeを使って実装されてみてはどうでしょうか? ただ、単純に終了するだけなので、タイムアウトしたかどうかを把握するのが難しいと思います。「起動ログがあって終了ログがなければ」みたいな条件で把握することはできるかもしれませんが、実装はそれなりに大変そうな気がします。 むしろ根本的な解決を目指して、サーバーを変える(レンタルサーバならVPSに変えるとか)とかの方が実は早い気もします
gU8C8Nud4E8p3uW

2022/05/03 16:16

RSSの読み込みって、そんなにリアルタイム性が必要なものなんでしょうか? サイトBに10人アクセスしたら10回RSSを取得しに行くのは馬鹿げているので、サイトB上にRSSをキャッシュしておく処理をサーバー上で数分おきに自動実行することを考えては。
AbeTakashi

2022/05/03 16:21

なるほど、負荷が高いのはキャッシュしてないからってのはありそうですね。キャッシュしてる前提の話かと思ってました。もちろん、キャッシュだと要件に適さないってこともあるでしょうが、まずはキャッシュする方向を模索した方が良いと思います。
honda_ta

2022/05/03 16:37

ご回答ありがとうございます。 事情を説明させていただきますと、 WordPressで作成している「サイトA」がエックスサーバーを使用していまして、 そのエックスサーバーで、少し前に大規模な障害が発生しました。 問題は、エックスサーバーではないサイトBにおいても、サイトAから更新情報を引っ張ってきていた関係上、 RSSの取得で処理待ちリクエストが増加し、ページが表示できなくなってしまったという事です。 RSSのキャッシュに関する問題も確かにありますが、今回はその問題とは切り分けて考えたいと思います。 兎も角、サイトAで障害などが発生した際に、サイトBまで問題が波及しないようにしたいとうのが最優先課題でございます。誠に申し訳ございません。 max_execution_timeの使い方がまだよく分かっていませんが、こちらの手法を少し試しています。
gU8C8Nud4E8p3uW

2022/05/03 16:56

サイトBへのアクセスをきっかけに都度RSSを取得しに行くのをやめましょうと提案します。サイトBに10人アクセスしたら10回、100人アクセスしたら100回、さほど頻繁に更新されないRSSを取得しに行くのは非効率的です。RSSを取得しに行くのをユーザーのアクセスをきっかけにせず、自動で数分周期で取得しに行きサイトB内にキャッシュしたら、アクセス頻度を抑えられ十分実用的に提供できると思われますが、いかがでしょうか。
gU8C8Nud4E8p3uW

2022/05/03 17:03

CURL接続のタイムアウトを60秒じゃなく短くしたらいいでしょうね、15秒でも十分長い気がしますが。
honda_ta

2022/05/03 17:14

ご返信ありがとうございます。 もう少し事情説明を追加しますと、 サイトAは「BuddyPress」というプラグインを使用して、SNS化しております。 参考 https://blog-bootcamp.jp/start/wordpress-buddypress/ リアルタイムで更新情報を反映したいという意向がありますのと、 サイトA側で大規模な障害が発生した際には、キャッシュで完全に問題が回避できるのかという懸念点もございます。 ですので、今回の問題とは出来れば切り分けて考えたいと思っております。 キャッシュの件は、別途、対応を考えさせていただければと思います。 誠に申し訳ございません… 「test.php」はどのようにタイムアウト処理を実装するかを考察するためのデモです。 実際のrssの取得にはこちらのライブラリを使用しております。 https://kana-lier.com/web/php_rssfeed/ 最終的にはここのサンプルphpにタイムアウト処理を仕込みたいです。 よろしくお願いいたします。
hentaiman

2022/05/04 01:50

サイトBからサイトAへアクセスした時だけサイトA側のtimeoutを3秒だか5秒だかにするようにちょいっとif分岐入れるだけで良くないですか
tabuu

2022/05/04 06:12

JavaScript(AJAX)でRSSを処理すればいいのではないでしょうか。 SEOに影響があるような箇所でも無さそうですし。
honda_ta

2022/05/04 10:17

hentaimankochinさん ご回答いただき、ありがとうございます。 すみません、その発想はありませんでした。サイトBからサイトAのRSSフィードにアクセスした時だけタイムアウトの時間を設ける設定をサイトA側で行うという事でしょうか? その処理を実装する方法について何卒、ご教授の程よろしくお願いいたします。
honda_ta

2022/05/04 10:24

tabuuさん ご回答いただき、ありがとうございます。 JavaScript(AJAX)でRSSを処理すればタイムアウト処理も実装可能でしょうか? phpの「max_execution_time」を使用した方法を色々と試してみたのですが、うまくいかず… ネットで調べたところ、以下のような問題があるらしいです。 参考 https://codesapuri.com/articles/php-set-time-limit ひょっとしたら以下のサイトの 「MAGPIE_FETCH_TIME_OUT」というものが使えるのかなとも思って試している最中なのですが… 参考 https://tenderfeel.xsrv.jp/wordpress/197/
tabuu

2022/05/04 12:04

>JavaScript(AJAX)でRSSを処理すればタイムアウト処理も実装可能でしょうか? 私は設定したことありませんが、AJAXのパラメータで設定可能のようです。
hentaiman

2022/05/04 13:06

curlする側(B)は特定のパラメーターかヘッダーを送って、受ける側(A)はそれが含まれている場合に限り ini_setとかset-time-limitで処理エラーにする時間を早めるだけですよ っていう感じで伝わりますかね

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る