forked from phacility/phabricator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPhabricatorDaemonReference.php
162 lines (131 loc) · 4.13 KB
/
PhabricatorDaemonReference.php
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
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<?php
final class PhabricatorDaemonReference extends Phobject {
private $name;
private $argv;
private $pid;
private $start;
private $pidFile;
private $daemonLog;
public static function loadReferencesFromFile($path) {
$pid_data = Filesystem::readFile($path);
try {
$dict = phutil_json_decode($pid_data);
} catch (PhutilJSONParserException $ex) {
$dict = array();
}
$refs = array();
$daemons = idx($dict, 'daemons', array());
$logs = array();
$daemon_ids = ipull($daemons, 'id');
if ($daemon_ids) {
try {
$logs = id(new PhabricatorDaemonLogQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withDaemonIDs($daemon_ids)
->execute();
} catch (AphrontQueryException $ex) {
// Ignore any issues here; getting this information only allows us
// to provide a more complete picture of daemon status, and we want
// these commands to work if the database is inaccessible.
}
$logs = mpull($logs, null, 'getDaemonID');
}
// Support PID files that use the old daemon format, where each overseer
// had exactly one daemon. We can eventually remove this; they will still
// be stopped by `phd stop --force` even if we don't identify them here.
if (!$daemons && idx($dict, 'name')) {
$daemons = array(
array(
'config' => array(
'class' => idx($dict, 'name'),
'argv' => idx($dict, 'argv', array()),
),
),
);
}
foreach ($daemons as $daemon) {
$ref = new PhabricatorDaemonReference();
// NOTE: This is the overseer PID, not the actual daemon process PID.
// This is correct for checking status and sending signals (the only
// things we do with it), but might be confusing. $daemon['pid'] has
// the daemon PID, and we could expose that if we had some use for it.
$ref->pid = idx($dict, 'pid');
$ref->start = idx($dict, 'start');
$config = idx($daemon, 'config', array());
$ref->name = idx($config, 'class');
$ref->argv = idx($config, 'argv', array());
$log = idx($logs, idx($daemon, 'id'));
if ($log) {
$ref->daemonLog = $log;
}
$ref->pidFile = $path;
$refs[] = $ref;
}
return $refs;
}
public function updateStatus($new_status) {
if (!$this->daemonLog) {
return;
}
try {
$this->daemonLog
->setStatus($new_status)
->save();
} catch (AphrontQueryException $ex) {
// Ignore anything that goes wrong here.
}
}
public function getPID() {
return $this->pid;
}
public function getName() {
return $this->name;
}
public function getArgv() {
return $this->argv;
}
public function getEpochStarted() {
return $this->start;
}
public function getPIDFile() {
return $this->pidFile;
}
public function getDaemonLog() {
return $this->daemonLog;
}
public function isRunning() {
return self::isProcessRunning($this->getPID());
}
public static function isProcessRunning($pid) {
if (!$pid) {
return false;
}
if (function_exists('posix_kill')) {
// This may fail if we can't signal the process because we are running as
// a different user (for example, we are 'apache' and the process is some
// other user's, or we are a normal user and the process is root's), but
// we can check the error code to figure out if the process exists.
$is_running = posix_kill($pid, 0);
if (posix_get_last_error() == 1) {
// "Operation Not Permitted", indicates that the PID exists. If it
// doesn't, we'll get an error 3 ("No such process") instead.
$is_running = true;
}
} else {
// If we don't have the posix extension, just exec.
list($err) = exec_manual('ps %s', $pid);
$is_running = ($err == 0);
}
return $is_running;
}
public function waitForExit($seconds) {
$start = time();
while (time() < $start + $seconds) {
usleep(100000);
if (!$this->isRunning()) {
return true;
}
}
return !$this->isRunning();
}
}