]> git.mxchange.org Git - friendica.git/blob - bin/daemon.php
adding parameter to App
[friendica.git] / bin / daemon.php
1 #!/usr/bin/env php
2 <?php
3 /**
4  * @file bin/daemon.php
5  * @brief Run the worker from a daemon.
6  *
7  * This script was taken from http://php.net/manual/en/function.pcntl-fork.php
8  */
9
10 use Friendica\App;
11 use Friendica\Core\Config;
12 use Friendica\Core\Worker;
13 use Friendica\Database\DBA;
14 use Friendica\Factory;
15 use Friendica\Util\BasePath;
16
17 // Get options
18 $shortopts = 'f';
19 $longopts = ['foreground'];
20 $options = getopt($shortopts, $longopts);
21
22 // Ensure that daemon.php is executed from the base path of the installation
23 if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
24         $directory = dirname($_SERVER["argv"][0]);
25
26         if (substr($directory, 0, 1) != "/") {
27                 $directory = $_SERVER["PWD"] . "/" . $directory;
28         }
29         $directory = realpath($directory . "/..");
30
31         chdir($directory);
32 }
33
34 require dirname(__DIR__) . '/vendor/autoload.php';
35
36 $basedir = BasePath::create(dirname(__DIR__), $_SERVER);
37 $configLoader = new Config\ConfigCacheLoader($basedir);
38 $config = Factory\ConfigFactory::createCache($configLoader);
39 $logger = Factory\LoggerFactory::create('daemon', $config);
40 $profiler = Factory\ProfilerFactory::create($logger, $config);
41
42 $a = new App($config, $logger, $profiler);
43
44 if ($a->getMode()->isInstall()) {
45         die("Friendica isn't properly installed yet.\n");
46 }
47
48 Config::load();
49
50 if (empty(Config::get('system', 'pidfile'))) {
51         die(<<<TXT
52 Please set system.pidfile in config/local.config.php. For example:
53     
54     'system' => [ 
55         'pidfile' => '/path/to/daemon.pid',
56     ],
57 TXT
58     );
59 }
60
61 $pidfile = Config::get('system', 'pidfile');
62
63 if (in_array("start", $_SERVER["argv"])) {
64         $mode = "start";
65 }
66
67 if (in_array("stop", $_SERVER["argv"])) {
68         $mode = "stop";
69 }
70
71 if (in_array("status", $_SERVER["argv"])) {
72         $mode = "status";
73 }
74
75 $foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options);
76
77 if (!isset($mode)) {
78         die("Please use either 'start', 'stop' or 'status'.\n");
79 }
80
81 if (empty($_SERVER["argv"][0])) {
82         die("Unexpected script behaviour. This message should never occur.\n");
83 }
84
85 $pid = null;
86
87 if (is_readable($pidfile)) {
88         $pid = intval(file_get_contents($pidfile));
89 }
90
91 if (empty($pid) && in_array($mode, ["stop", "status"])) {
92         Config::set('system', 'worker_daemon_mode', false);
93         die("Pidfile wasn't found. Is the daemon running?\n");
94 }
95
96 if ($mode == "status") {
97         if (posix_kill($pid, 0)) {
98                 die("Daemon process $pid is running.\n");
99         }
100
101         unlink($pidfile);
102
103         Config::set('system', 'worker_daemon_mode', false);
104         die("Daemon process $pid isn't running.\n");
105 }
106
107 if ($mode == "stop") {
108         posix_kill($pid, SIGTERM);
109
110         unlink($pidfile);
111
112         $logger->notice("Worker daemon process was killed", ["pid" => $pid]);
113
114         Config::set('system', 'worker_daemon_mode', false);
115         die("Worker daemon process $pid was killed.\n");
116 }
117
118 if (!empty($pid) && posix_kill($pid, 0)) {
119         die("Daemon process $pid is already running.\n");
120 }
121
122 $logger->notice('Starting worker daemon.', ["pid" => $pid]);
123
124 if (!$foreground) {
125         echo "Starting worker daemon.\n";
126
127         // Switch over to daemon mode.
128         if ($pid = pcntl_fork()) {
129                 return;     // Parent
130         }
131
132         fclose(STDIN);  // Close all of the standard
133
134         // Enabling this seem to block a running php process with 100% CPU usage when there is an outpout
135         // fclose(STDOUT); // file descriptors as we
136         // fclose(STDERR); // are running as a daemon.
137
138         DBA::disconnect();
139
140         register_shutdown_function('shutdown');
141
142         if (posix_setsid() < 0) {
143                 return;
144         }
145
146         if ($pid = pcntl_fork()) {
147                 return;     // Parent
148         }
149
150         $pid = getmypid();
151         file_put_contents($pidfile, $pid);
152
153         // We lose the database connection upon forking
154         $a->loadDatabase();
155 }
156
157 Config::set('system', 'worker_daemon_mode', true);
158
159 // Just to be sure that this script really runs endlessly
160 set_time_limit(0);
161
162 $wait_interval = intval(Config::get('system', 'cron_interval', 5)) * 60;
163
164 $do_cron = true;
165 $last_cron = 0;
166
167 // Now running as a daemon.
168 while (true) {
169         if (!$do_cron && ($last_cron + $wait_interval) < time()) {
170                 $logger->info('Forcing cron worker call.', ["pid" => $pid]);
171                 $do_cron = true;
172         }
173
174         Worker::spawnWorker($do_cron);
175
176         if ($do_cron) {
177                 // We force a reconnect of the database connection.
178                 // This is done to ensure that the connection don't get lost over time.
179                 DBA::reconnect();
180
181                 $last_cron = time();
182         }
183
184         $logger->info("Sleeping", ["pid" => $pid]);
185         $start = time();
186         do {
187                 $seconds = (time() - $start);
188
189                 // logarithmic wait time calculation.
190                 // Background: After jobs had been started, they often fork many workers.
191                 // To not waste too much time, the sleep period increases.
192                 $arg = (($seconds + 1) / ($wait_interval / 9)) + 1;
193                 $sleep = round(log10($arg) * 1000000, 0);
194                 usleep($sleep);
195
196                 $timeout = ($seconds >= $wait_interval);
197         } while (!$timeout && !Worker::IPCJobsExists());
198
199         if ($timeout) {
200                 $do_cron = true;
201                 $logger->info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
202         } else {
203                 $do_cron = false;
204                 $logger->info("Worker jobs are calling to be forked.", ["pid" => $pid]);
205         }
206 }
207
208 function shutdown() {
209         posix_kill(posix_getpid(), SIGHUP);
210 }