2009-04-15 36 views
14

Vấn đề: Tôi muốn thực hiện một số quy trình xử lý công việc php đang lắng nghe trên hàng đợi MQ-server cho các công việc không đồng bộ. Vấn đề bây giờ là chỉ cần chạy các tiến trình này như các daemon trên một máy chủ không thực sự cho tôi bất kỳ mức độ kiểm soát nào đối với các cá thể (Load, Status, bị khóa) ... ngoại trừ có thể để đổ ps -aux. Do đó tôi đang tìm một môi trường thời gian chạy của một số loại cho phép tôi theo dõi và kiểm soát các trường hợp, hoặc ở cấp độ hệ thống (quá trình) hoặc trên một lớp cao hơn (một số loại máy chủ ứng dụng kiểu Java)PHP Daemon/môi trường công nhân

Bất kỳ con trỏ?

+0

Xem thêm: http://symfony.com/doc/master/components/process.html –

Trả lời

12

Dưới đây là một số mã có thể hữu ích.

<? 
define('WANT_PROCESSORS', 5); 
define('PROCESSOR_EXECUTABLE', '/path/to/your/processor'); 
set_time_limit(0); 
$cycles = 0; 
$run = true; 
$reload = false; 
declare(ticks = 30); 

function signal_handler($signal) { 
    switch($signal) { 
    case SIGTERM : 
     global $run; 
     $run = false; 
     break; 
    case SIGHUP : 
     global $reload; 
     $reload = true; 
     break; 
    } 
} 

pcntl_signal(SIGTERM, 'signal_handler'); 
pcntl_signal(SIGHUP, 'signal_handler'); 

function spawn_processor() { 
    $pid = pcntl_fork(); 
    if($pid) { 
     global $processors; 
     $processors[] = $pid; 
    } else { 
     if(posix_setsid() == -1) 
      die("Forked process could not detach from terminal\n"); 
     fclose(stdin); 
     fclose(stdout); 
     fclose(stderr); 
     pcntl_exec(PROCESSOR_EXECUTABLE); 
     die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n"); 
    } 
} 

function spawn_processors() { 
    global $processors; 
    if($processors) 
     kill_processors(); 
    $processors = array(); 
    for($ix = 0; $ix < WANT_PROCESSORS; $ix++) 
     spawn_processor(); 
} 

function kill_processors() { 
    global $processors; 
    foreach($processors as $processor) 
     posix_kill($processor, SIGTERM); 
    foreach($processors as $processor) 
     pcntl_waitpid($processor); 
    unset($processors); 
} 

function check_processors() { 
    global $processors; 
    $valid = array(); 
    foreach($processors as $processor) { 
     pcntl_waitpid($processor, $status, WNOHANG); 
     if(posix_getsid($processor)) 
      $valid[] = $processor; 
    } 
    $processors = $valid; 
    if(count($processors) > WANT_PROCESSORS) { 
     for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--) 
      posix_kill($processors[$ix], SIGTERM); 
     for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--) 
      pcntl_waitpid($processors[$ix]); 
    } elseif(count($processors) < WANT_PROCESSORS) { 
     for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++) 
      spawn_processor(); 
    } 
} 

spawn_processors(); 

while($run) { 
    $cycles++; 
    if($reload) { 
     $reload = false; 
     kill_processors(); 
     spawn_processors(); 
    } else { 
     check_processors(); 
    } 
    usleep(150000); 
} 
kill_processors(); 
pcntl_wait(); 
?> 
+0

Bạn nhận được thông tin này ở đâu? Dự án nguồn mở hoặc mã của riêng bạn? Bất kỳ tài liệu hoặc giải thích về những gì chính xác đang xảy ra ở đây? – leek

+0

Mã của riêng tôi. Tôi không có khuynh hướng giải thích nó, không. – chaos

+0

Ngoài ra, https://github.com/kvz/system_daemon. – HyderA

1

Bạn có thực sự cần nó liên tục chạy không?

Nếu bạn chỉ muốn sinh ra quy trình mới theo yêu cầu, bạn có thể đăng ký nó như một dịch vụ trong xinetd.

+0

Các khía cạnh sinh sản không phải là một vấn đề lớn imho vì số lượng công nhân phụ thuộc vào hiệu năng hệ thống thường là hằng số. Quan trọng hơn sẽ là khía cạnh giám sát của tình trạng công nhân cá nhân (bị rơi, bất cứ điều gì). Một công cụ tôi vừa phát hiện ra có thể là DJBs deamontools – Sebastian

+0

Đó là một tùy chọn. Để theo dõi bạn cũng có thể sử dụng tập tin PID(). Khi sụp đổ tất cả các khóa được phát hành. – vartec

4

Có vẻ như bạn đã có MQ và chạy trên hệ thống * nix và chỉ muốn có cách quản lý công nhân.

Cách đơn giản để thực hiện việc này là sử dụng màn hình GNU. Để bắt đầu 10 công nhân, bạn có thể sử dụng:

#!/bin/sh 
for x in `seq 1 10` ; do 
screen -dmS worker_$x php /path/to/script.php worker$x 
end 

Điều này sẽ bắt đầu 10 công nhân ở chế độ nền sử dụng màn hình có tên worker_1,2,3 v.v.

Bạn có thể gắn lại màn hình bằng cách chạy màn hình -r worker_ và liệt kê các nhân viên đang chạy bằng cách sử dụng danh sách màn hình.

Để biết thêm thông hướng dẫn này có thể được giúp đỡ: http://www.kuro5hin.org/story/2004/3/9/16838/14935

Cũng thử:

  • màn hình --help
  • man màn hình
  • hoặc google.

Đối với máy chủ sản xuất, tôi thường khuyên bạn nên sử dụng tập lệnh khởi động hệ thống bình thường, nhưng tôi đã chạy lệnh màn hình từ tập lệnh khởi động trong nhiều năm mà không gặp vấn đề gì.

0

Bellow là thực hiện làm việc của chúng ta về câu trả lời @chaos. Mã để xử lý tín hiệu đã bị xóa vì tập lệnh này thường chỉ mất vài phần nghìn giây.

Ngoài ra, trong mã, chúng tôi đã thêm 2 chức năng để tiết kiệm pids giữa các cuộc gọi: restore_processors_state() và save_processors_state(). Chúng tôi đã sử dụng redis ở đó, nhưng bạn có thể quyết định sử dụng triển khai trên các tệp.

Chúng tôi chạy tập lệnh này mỗi phút bằng cách sử dụng cron. Cron kiểm tra xem tất cả các tiến trình có còn sống hay không. Nếu không - nó chạy lại chúng và sau đó chết. Nếu chúng ta muốn giết các tiến trình hiện có thì chúng ta chỉ cần chạy tập lệnh này với đối số kill: php script.php kill.

Cách tiện dụng để chạy công nhân mà không cần tiêm tập lệnh vào init.d.

<?php 

include_once dirname(__FILE__) . '/path/to/bootstrap.php'; 

define('WANT_PROCESSORS', 5); 
define('PROCESSOR_EXECUTABLE', '' . dirname(__FILE__) . '/path/to/worker.php'); 
set_time_limit(0); 

$run = true; 
$reload = false; 
declare(ticks = 30); 

function restore_processors_state() 
{ 
    global $processors; 

    $redis = Zend_Registry::get('redis'); 
    $pids = $redis->hget('worker_procs', 'pids'); 

    if(!$pids) 
    { 
     $processors = array(); 
    } 
    else 
    { 
     $processors = json_decode($pids, true); 
    } 
} 

function save_processors_state() 
{ 
    global $processors; 

    $redis = Zend_Registry::get('redis'); 
    $redis->hset('worker_procs', 'pids', json_encode($processors)); 
} 

function spawn_processor() { 
    $pid = pcntl_fork(); 
    if($pid) { 
     global $processors; 
     $processors[] = $pid; 
    } else { 
     if(posix_setsid() == -1) 
      die("Forked process could not detach from terminal\n"); 
     fclose(STDIN); 
     fclose(STDOUT); 
     fclose(STDERR); 
     pcntl_exec('/usr/bin/php', array(PROCESSOR_EXECUTABLE)); 
     die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n"); 
    } 
} 

function spawn_processors() { 
    restore_processors_state(); 

    check_processors(); 

    save_processors_state(); 
} 

function kill_processors() { 
    global $processors; 
    foreach($processors as $processor) 
     posix_kill($processor, SIGTERM); 
    foreach($processors as $processor) 
     pcntl_waitpid($processor, $trash); 
    unset($processors); 
} 

function check_processors() { 
    global $processors; 
    $valid = array(); 
    foreach($processors as $processor) { 
     pcntl_waitpid($processor, $status, WNOHANG); 
     if(posix_getsid($processor)) 
      $valid[] = $processor; 
    } 
    $processors = $valid; 
    if(count($processors) > WANT_PROCESSORS) { 
     for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--) 
      posix_kill($processors[$ix], SIGTERM); 
     for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--) 
      pcntl_waitpid($processors[$ix], $trash); 
    } 
    elseif(count($processors) < WANT_PROCESSORS) { 
     for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++) 
      spawn_processor(); 
    } 
} 

if(isset($argv) && count($argv) > 1) { 
    if($argv[1] == 'kill') { 
     restore_processors_state(); 
     kill_processors(); 
     save_processors_state(); 

     exit(0); 
    } 
} 

spawn_processors(); 
Các vấn đề liên quan