经过多年在其他人的帖子中寻找答案,我终于要问了。
我正在尝试实现一个WatchDog / Shepherd模式来监视在我的应用程序中运行的长进程(从2-3分钟到几个小时)。
该应用程序相当复杂,我在项目中期开始研究它,所以我没有完全掌握它。
两台服务器正在运行:我们称之为FACADE,Apache / 2.4.10(Debian)和CALCULUS,以及Apache / 2.4.6(Red Hat Enterprise Linux)。
我设计了这样的东西:
我的朋友,纯粹是理论。现在来了实施:
/**
*Implements the Singleton Design Pattern
*And of course, the Watchdog Pattern, using a Socket to communicate with the Shepherd.
*/
class Watchdog{
/** Singleton Design pattern. Use $watchdog = Watchdog::getInstance() to use the doggy */
private static $instance = null;
private function __construct(){
$this->init();
}
public static function getInstance(){
if (Watchdog::$instance === null)
Watchdog::$instance = new Watchdog();
return Watchdog::$instance;
}
private $socket;
private $connected = false;
private function init(){
$this->socket = fsockopen("tcp://A.B.C.D", 4242, $errno, $errstr);
if($this->socket === false){
echo "$errno : $errstr";
}else{
$this->connected = true;
}
}
public function kill(){
fclose($this->socket);
Watchdog::$instance = null;
}
public function bark($message){
if($this->connected === true){
fwrite($this->socket, "M#".$message."\n");
}
}
public function alert($err){
if($this->connected === true){
fwrite($this->socket, "E#".$err."\n");
}
}
}
?>
Shepeherd:
/**Implements the Singleton Design Pattern,
* And the Shepherd / Watchdog Patter, using a Socket to communicate with the Watchdog.
*/
class Shepherd{
/** Singleton Design pattern. Use $shepherd = Shepherd::GetInstance() to use the shepherd */
private static $instance;
private function __construct()
{
$this->init();
}
public static function GetInstance(){
if (self::$instance === null)
self::$instance = new Shepherd();
return self::$instance;
}
/**Instance variables **/
private $socket;
public $initialised = false;
public $doggyConnected = false;
private $dogsocket;
/**Init : Initializes the shephrd by binding it to the watchdog on the 4242 port**/
private function init(){
ob_implicit_flush();
$this->socket = stream_socket_server("tcp://0.0.0.0:4242", $errno, $errstr);
$this->initialised = true;
}
/**Sit And Wait : Waits for Dog connection**/
public function sitandwait(){
//Waiting for doggy connection
do {
if (($this->dogsocket = stream_socket_accept($this->socket)) === false) {
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($this->dogsocket)) . "\n";
break;
}else{
$this->doggyConnected = true;
}
}while($this->doggyConnected === false);
}
/**Listen to Dog : Waits for Dog to send a message and echoes it **/
public function listentodog(){
if($this->dogsocket !== false) {
$buf = fgets($this->dogsocket);
return $buf;
}
}
/**Kill : Kills the shepherd and closes connections **/
private function kill(){
stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
stream_socket_shutdown($this->dogsocket, STREAM_SHUT_RDWR);
fclose ($this->dogsocket);
fclose ($this->socket);
Shepherd::$instance = null;
}
/**Run : Runs the Shepherd till he got a message from dog **/
public function run(){
if($this->doggyConnected === false)
$this->sitandwait();
return $this->listentodog();
}
}
在真正的网站上尝试了那些没有成功之后,我决定试着看看两台服务器上发生了什么,多亏了netcat命令。
有一个问题:当我通过netcat伪造牧羊人时,狗可以连接并发送有关过程的准确数据。当我通过netcat --send-only伪造狗时,Shepherd获取数据并用它们做正确的事情。
但是,当我从应用程序中运行时,我得到了一个“Connexion拒绝”的狗 - > init()(fsockopen:Connexionrefusée),当然,牧羊人死于超时。
但等等还有更多!! 您可能认为问题来自连接,而netcat则没有出现因为我没有从PHP连接(或者我没有连接)到PHP打开的套接字)。
我也这么认为;我编写了两个脚本test_dog.php和test_shepherd.php,它们的使用方式与我实际应用程序中的方式完全相同。当我试图让他们沟通时,它的作用!它甚至适用于真正的狗(监控真实的应用程序进程)和test_shepherd.php,或者使用真正的Shepherd(来自我的应用程序)和test_watchdog.php
我决定来这里向你们求助,因为我完全迷失了。我不明白为什么它不能与真正的代码一起使用,而是与test_脚本一起使用。在那些中,我确保使用与实际应用程序完全相同的方式。
为了向您展示一切,这是我的test_脚本:
test_watchdog.php
require "Watchdog.php";
$dog = Watchdog::getInstance();
$dog->bark("Try try try");
$dog->bark("Trying hard !!");
sleep(5);
$dog->bark("Trying harder to see...");
sleep(2);
$dog->bark("END");
$dog->kill();
test_shepherd.php
require "Shepherd.php";
$shep = new _Shepherd();
echo $shep->run();
......我认为这就是全部。请回答你是否有可能帮助我的最微弱的想法,你是我最后的希望,我迷失了,绝望...... 提前谢谢你:)
编辑:在CALCULUS上,Watchdog由一个名为Process(运行主进程)的千行长类调用。关键是能够在代码中的几乎所有位置调用Watchdog,用户可能必须等待。
这里是例如Process的__construct,初始化Watchdog,以及调用$ doggy-> bark()的方法之一;
public function __construct($photoId = 0) {
$this->params = array();
$this->doggy = Watchdog::GetInstance();
$this->params['photoid'] = $photoId ;
date_default_timezone_set ('Europe/Paris');
}
public function transfertProject() {
try {
$this->doggy->bark('s#transfert');
//Traitement long
set_time_limit (0);
ini_set('post_max_size', 0);
ini_set('upload_max_filesize', 0);
$response = false;
if (!isset($_FILES['file'])) {
$post_max_size = ini_get('post_max_size');
$upload_max_size = ini_get('upload_max_filesize');
return "Le fichier ne semble pas avoir été posté, vérifier la taille maximal d'upload";
}
$name = $_FILES['file']['name'];
$filename = "../Workspace/projects/".$name;
$tmp = $_FILES['file']['tmp_name'];
if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
$response = $this->unzipProjectArchive();
unlink($filename);
}
$this->doggy->bark('c#transfert');
return $response;
} // END TRY
catch (Exception $ex) {
//Watchdog telling shepherd
$this->doggy->alert('transfert');
}
}