Skip to content

Commit b4a3d39

Browse files
committed
Implemented standard entry point bin/lrpm
1 parent f93671d commit b4a3d39

4 files changed

Lines changed: 81 additions & 11 deletions

File tree

README.adoc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ PHP-LRPM uses exponential backoff when attempting to restart a process; some pro
3838

3939
== Non-goals
4040

41-
Currently LRPM is not intended to run as PID 1, nor was it tested in this role.
41+
Currently, LRPM is not intended to run as PID 1, nor was it tested in this role.
4242

4343
== Usage
4444

45-
1. Implement the `ConfigurationSource`. This interface exposes a public method `loadConfiguration()`, that returns an associative array containing the configuration for all the workers (see details below).
46-
2. Implement the `Worker`. This interface exposes two public methods, `start()` and `cycle()`. The child process will call `start()`, passing the worker configuration as an argument, and then enter an endless loop, where it calls `cycle()`, and then checks for a shutdown condition (usually, the termination of the LRPM supervisor process). Backoff should be implemented at the end of the `cycle()` method, as we dispatch signal handlers right after `cycle()` returns. Be careful not to run a tight loop at times when cycles are not doing actual work!
45+
1. Implement one or more `Worker` classes. This interface exposes two public methods, `start()` and `cycle()`. The child process will call `start()`, passing the worker configuration as an argument, and then enter an endless loop, where it calls `cycle()`, and then checks for a shutdown condition (usually, the termination of the LRPM supervisor process). Backoff should be implemented at the end of the `cycle()` method, as we dispatch signal handlers right after `cycle()` returns. Be careful not to run a tight loop at times when cycles are not doing actual work!
46+
2. Implement the `ConfigurationSource` class. This interface exposes a public method `loadConfiguration()`, that returns an associative array containing the configuration for all the workers (see example and full documentation in the `Job configuration` subsection).
47+
3. Run `bin/rlpm` with your configuration class as an argument, e.g. `bin/rlpm '\MyNamespace\MyConfigurationSource'`
4748

4849
=== Job configuration
4950

@@ -116,9 +117,11 @@ Worker process installs default signal handlers for SIGTERM and SIGINT. Signal h
116117

117118
You can implement and install your own signal handlers inside your Worker implementation, but make sure that your Worker process shuts down cleanly after receiving SIGTERM, otherwise the LRPM supervisor will consider it unresponsive and follow up with a SIGKILL.
118119

119-
=== Misc caveats
120+
=== Implementing a custom entry point
120121

121-
Be aware that code in your entry point will run in the supervisor (parent) process, while your `Worker` classes will run in child processes. The entry point should do no more than set up the autoloader and run the `ProcessManager`. Sharing open sockets between parent and children through `fork(2)` is not safe. Worker processes should connect to wherever they need to connect to only after they have been spawned.
122+
If you need to implement a custom entry point for LRPM, be aware that the code in your custom entry point will run in the supervisor (parent) process, while your `Worker` classes will run in child processes `fork(2)`-ed from the supervisor. The entry point should do no more than set up the autoloader and run the `ProcessManager`. Any open file descriptors apart from stdin/stdout/stderr should be closed before entering the event loop (`ProcessManager->run()`). Sharing open sockets between parent and children through `fork(2)` is not safe! Worker processes should connect to wherever they need to connect to only after they have been spawned.
123+
124+
If unsure, use the provided `bin/lrpm` entry point.
122125

123126
== Operating LRPM
124127

README.in.adoc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ PHP-LRPM uses exponential backoff when attempting to restart a process; some pro
3838

3939
== Non-goals
4040

41-
Currently LRPM is not intended to run as PID 1, nor was it tested in this role.
41+
Currently, LRPM is not intended to run as PID 1, nor was it tested in this role.
4242

4343
== Usage
4444

45-
1. Implement the `ConfigurationSource`. This interface exposes a public method `loadConfiguration()`, that returns an associative array containing the configuration for all the workers (see details below).
46-
2. Implement the `Worker`. This interface exposes two public methods, `start()` and `cycle()`. The child process will call `start()`, passing the worker configuration as an argument, and then enter an endless loop, where it calls `cycle()`, and then checks for a shutdown condition (usually, the termination of the LRPM supervisor process). Backoff should be implemented at the end of the `cycle()` method, as we dispatch signal handlers right after `cycle()` returns. Be careful not to run a tight loop at times when cycles are not doing actual work!
45+
1. Implement one or more `Worker` classes. This interface exposes two public methods, `start()` and `cycle()`. The child process will call `start()`, passing the worker configuration as an argument, and then enter an endless loop, where it calls `cycle()`, and then checks for a shutdown condition (usually, the termination of the LRPM supervisor process). Backoff should be implemented at the end of the `cycle()` method, as we dispatch signal handlers right after `cycle()` returns. Be careful not to run a tight loop at times when cycles are not doing actual work!
46+
2. Implement the `ConfigurationSource` class. This interface exposes a public method `loadConfiguration()`, that returns an associative array containing the configuration for all the workers (see example and full documentation in the `Job configuration` subsection).
47+
3. Run `bin/rlpm` with your configuration class as an argument, e.g. `bin/rlpm '\MyNamespace\MyConfigurationSource'`
4748

4849
=== Job configuration
4950

@@ -79,9 +80,11 @@ Worker process installs default signal handlers for SIGTERM and SIGINT. Signal h
7980

8081
You can implement and install your own signal handlers inside your Worker implementation, but make sure that your Worker process shuts down cleanly after receiving SIGTERM, otherwise the LRPM supervisor will consider it unresponsive and follow up with a SIGKILL.
8182

82-
=== Misc caveats
83+
=== Implementing a custom entry point
8384

84-
Be aware that code in your entry point will run in the supervisor (parent) process, while your `Worker` classes will run in child processes. The entry point should do no more than set up the autoloader and run the `ProcessManager`. Sharing open sockets between parent and children through `fork(2)` is not safe. Worker processes should connect to wherever they need to connect to only after they have been spawned.
85+
If you need to implement a custom entry point for LRPM, be aware that the code in your custom entry point will run in the supervisor (parent) process, while your `Worker` classes will run in child processes `fork(2)`-ed from the supervisor. The entry point should do no more than set up the autoloader and run the `ProcessManager`. Any open file descriptors apart from stdin/stdout/stderr should be closed before entering the event loop (`ProcessManager->run()`). Sharing open sockets between parent and children through `fork(2)` is not safe! Worker processes should connect to wherever they need to connect to only after they have been spawned.
86+
87+
If unsure, use the provided `bin/lrpm` entry point.
8588

8689
== Operating LRPM
8790

bin/lrpm

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env php
2+
<?php
3+
declare(strict_types=1);
4+
error_reporting(E_ALL);
5+
6+
const EXIT_SUCCESS = 0;
7+
const EXIT_USAGE = 64;
8+
const EXIT_AUTOLOADER_NOT_FOUND = 1;
9+
const EXIT_CONFIG_SOURCE_CLASS_NOT_FOUND = 2;
10+
11+
$shortopts = 'h';
12+
$longopts = [
13+
'help'
14+
];
15+
$options = getopt($shortopts, $longopts, $rest_index);
16+
$progname = basename($argv[0]);
17+
$helpmsg = "Usage: $progname [options] <configuration-class>
18+
19+
Options:
20+
-h, --help display this help and exit
21+
";
22+
23+
if (array_key_exists('h', $options) || array_key_exists('help', $options)) {
24+
fwrite(STDERR, $helpmsg);
25+
exit(EXIT_USAGE);
26+
}
27+
28+
$rest = array_slice($argv, $rest_index);
29+
if (count($rest) < 1) {
30+
fwrite(STDERR, $helpmsg);
31+
exit(EXIT_USAGE);
32+
}
33+
34+
$configSourceClass = $rest[0];
35+
36+
probeForAutoloader($progname);
37+
38+
if (!class_exists($configSourceClass)) {
39+
fwrite(STDERR, "Cannot find class: $configSourceClass" . PHP_EOL);
40+
exit(EXIT_CONFIG_SOURCE_CLASS_NOT_FOUND);
41+
}
42+
43+
use PHPLRPM\ProcessManager;
44+
45+
$processManager = new ProcessManager($configSourceClass);
46+
$processManager->run();
47+
48+
function probeForAutoloader($programName): void
49+
{
50+
$autoloadLocations = [
51+
__DIR__ . '/../vendor/autoload.php',
52+
__DIR__ . '/../../../autoload.php'
53+
];
54+
55+
foreach ($autoloadLocations as $autoloadFile) {
56+
if (file_exists($autoloadFile)) {
57+
require_once($autoloadFile);
58+
return;
59+
}
60+
}
61+
62+
fwrite(STDERR, $programName . ': could not find autoload.php, use PHP Composer to generate autoloader code' . PHP_EOL);
63+
exit(EXIT_AUTOLOADER_NOT_FOUND);
64+
}

bin/lrpmctl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ $longopts = [
1818
];
1919
$options = getopt($shortopts, $longopts, $rest_index);
2020
$progname = basename($argv[0]);
21-
$helpmsg = "Usage: $progname [<options>] <message>
21+
$helpmsg = "Usage: $progname [options] <message>
2222
2323
Options:
2424
-h, --help display this help and exit

0 commit comments

Comments
 (0)