此文主要解决部分基于NPHP的站点在做大之后,因cleanup相关清理程序超时无法正常运行,导致出现用户等级、做种魔力无法正常更新等情况。主要可能的报错和原因为:
- 站点使用Cloudflare作为CDN,因为清理程序运行超过100s,被强制522超时停止运行。
- 站点Nginx设置后端超时时间过短,导致502报错。
以下讲解和代码patch均基于本人fork的官方源码 Rhilip/NexusPHP(v1.5.beta5.20120707),不提供除本文外的任何形式的说明以及免费讲解。如果你非NPHP架构或者你站点规模还达不到出现cleanup超时,请勿了解!!
cleanup长耗时任务分析
通过对原有include/cleanup.php中的printProgress方法进行修改,我们可以发现以下任务均为长耗时任务
- calculate seeding bonus (做种魔力值计算)
- update count of seeders, leechers, comments for torrents (种子做种以及评论情况更新)
具体耗时视站内做种人数以及种子相关表大小而定,一般来说如果NPHP宿主机性能较差,在peers表突破1w行之后,做种魔力清算就会突破60s限制(Nginx默认超时时间)。而种子表突破5k行之后,种子情况更新也会突破相关限制。(以上行数均为本人瞎写瞎编)
此外,这两个长耗时任务均处在清理程序首部,容易因为超时自动退出,而且NPHP默认是通过register_shutdown_function("autoclean")的形式进行执行,导致后续清理程序无法正常运行。
考虑通过以下方式进行优化:
- 去除Nginx服务超时限制,本地使用crontab定时wget请求cron.php页面。具体方法可见NPHP中
include/config.php说明。 - 使用PHP_CLI运行
cron.php文件,绕过Web服务器的相关超时设置。这也是本文的相关说明要点。
相关修改说明
将cleanup相关方法托给cron,而不是shutdown_function。此步只需要修改config.php文件即可,将全部变量
$useCronTriggerCleanUp改为true值即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34Index: include/functions.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- include/functions.php (revision e97ab8f41738d550ec9dff6b1d16fc814fdb8eb5)
+++ include/functions.php (date 1579598707415)
mysql_select_db($mysql_db) or die('dbconn: mysql_select_db: ' + mysql_error());
userlogin();
-
- if (!$useCronTriggerCleanUp && $autoclean) {
- register_shutdown_function("autoclean");
- }
}
function get_user_row($id)
{
Index: include/config.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- include/config.php (revision e97ab8f41738d550ec9dff6b1d16fc814fdb8eb5)
+++ include/config.php (date 1579597884946)
//Make sure you have wget installed on your OS
//replace "http://www.nexusphp.com/" with your own site address
-$useCronTriggerCleanUp = false;
+$useCronTriggerCleanUp = true;
//some promotion rules
//$promotionrules_torrent = array(0 => array("mediumid" => array(1), "promotion" => 5), 1 => array("mediumid" => array(3), "promotion" => 5), 2 => array("catid" => array(402), "standardid" => array(3), "promotion" => 4), 3 => array("catid" => array(403), "standardid" => array(3), "promotion" => 4));
$promotionrules_torrent = array();限制
cron.php的运行环境,在cron.php文件头部增加以下代码进行限制1
2
3
4if (PHP_SAPI != 'cli') {
header("HTTP/1.0 403 Forbidden");
die('RUN in CLI');
}将
autoclean()方法从function.php中移出,并增加启动命令--print,--force-all1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76Index: include/functions.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- include/functions.php (revision e97ab8f41738d550ec9dff6b1d16fc814fdb8eb5)
+++ include/functions.php (date 1579598186100)
}
}
-function autoclean() {
- global $autoclean_interval_one, $rootpath;
- $now = TIMENOW;
- $res = sql_query("SELECT value_u FROM avps WHERE arg = 'lastcleantime'");
- $row = mysql_fetch_array($res);
- if (!$row) {
- sql_query("INSERT INTO avps (arg, value_u) VALUES ('lastcleantime',$now)") or sqlerr(__FILE__, __LINE__);
- return false;
- }
- $ts = $row[0];
- if ($ts + $autoclean_interval_one > $now) {
- return false;
- }
- sql_query("UPDATE avps SET value_u=$now WHERE arg='lastcleantime' AND value_u = $ts") or sqlerr(__FILE__, __LINE__);
- if (!mysql_affected_rows()) {
- return false;
- }
- require_once($rootpath . 'include/cleanup.php');
- return docleanup();
-}
function unesc($x) {
return $x;
Index: cron.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- cron.php (revision e97ab8f41738d550ec9dff6b1d16fc814fdb8eb5)
+++ cron.php (date 1579598452935)
<?php
require_once("include/bittorrent.php");
dbconn();
+
+function autoclean() {
+ global $argv;
+ global $autoclean_interval_one, $rootpath;
+ $now = TIMENOW;
+
+ $force_all = PHP_SAPI == 'cli' ? in_array('--force_all', $argv) : false;
+ $print = PHP_SAPI == 'cli' ? in_array('--print', $argv) : false;
+
+ $res = sql_query("SELECT value_u FROM avps WHERE arg = 'lastcleantime'");
+ $row = mysql_fetch_array($res);
+ if (!$row) {
+ sql_query("INSERT INTO avps (arg, value_u) VALUES ('lastcleantime',$now)") or sqlerr(__FILE__, __LINE__);
+ return false;
+ }
+ $ts = $row[0];
+ if ($ts + $autoclean_interval_one > $now) {
+ return false;
+ }
+ sql_query("UPDATE avps SET value_u=$now WHERE arg='lastcleantime' AND value_u = $ts") or sqlerr(__FILE__, __LINE__);
+ if (!mysql_affected_rows()) {
+ return false;
+ }
+ require_once($rootpath . 'include/cleanup.php');
+ return docleanup($force_all, $print);
+}
+
if ($useCronTriggerCleanUp) {
$return = autoclean();
if ($return) {在做完前三步之后,我们就可以使用
php /path/to/cron.php --print相关命令直接运行NPHP的清理程序。因为dbconn方法中自带了userlogin方法,所以我们在CLI环境中要禁止其使用userlogin的运行,简单处理如下
1
if (PHP_SAPI != 'cli') userlogin();
设置crontab,具体如下
1
*/5 * * * * php /path/to/cron.php
