Archive: Namaste PHP AMQP framework v1.0 (2017-2020)

952 days continuous production uptime, 40k+ tp/s single node.
Original corpo Bitbucket history not included — clean archive commit.
This commit is contained in:
2026-04-05 09:49:30 -07:00
commit 373ebc8c93
1284 changed files with 409372 additions and 0 deletions

View File

@@ -0,0 +1,366 @@
<?php
/**
* This is a wrapper class for the AT daemon. It was plagiarized from:
*
* https://github.com/treffynnon/PHP-at-Job-Queue-Wrapper/blob/master/lib/Treffynnon/At/Wrapper.php
*
* Because the original (author's) version uses exceptions for error reporting. I've re-tooled the original code,
* eliminating the exception processing, making the output logging align with Namaste's logging formats, and closing
* access publicly to all methods except the intended public function.
*
* @author treffynnon@php.net Simon Holywell
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 06-07-17 mks port from original source
* 08-17-20 mks DB-168: code review
*
*/
class gacATWrapper
{
protected static string $binary = 'at'; // path to the AT binary
protected static string $addRegex = '/^job (\d+) at ([\w\d- :]+)$/'; // regexp to fetch the current job listings
protected static array $addMap = array( // regexp mapping -> descriptive names
1 => 'job_number',
2 => 'date',
);
// regexp for fetching queue info
protected static string $queueRegex = '/^(\d+)\s+([\w\d- :]+) (\w) ([\w-]+)$/';
// another regexp matching for queue data
protected static array $queueMap = array(
1 => 'job_number',
2 => 'date',
3 => 'queue',
4 => 'user',
);
protected static string $res = 'CRON: ';
protected static string $pipeTo = '2>&1'; // redirects STDERR to STDOUT (redundant)
protected static array $atSwitches = array( // supported AT options list
'queue' => '-q',
'list_queue' => '-l',
'file' => '-f',
'remove' => '-d',
);
/**
* cmd() -- public static function
*
* @users self::addCommand
*
* @param $command
* @param $time
* @param null $queue
* @return mixed
*/
static public function cmd($command, $time, $queue = null)
{
return self::addCommand($command, $time, $queue);
}
/**
* @uses self::addFile
*
* @param $file
* @param $time
* @param null $queue
* @return mixed
*/
static public function file($file, $time, $queue = null)
{
return self::addFile($file, $time, $queue);
}
/**
* @uses self::listQueue
*
* @param null $queue
* @return mixed
*/
static public function lq($queue = null)
{
return self::listQueue($queue);
}
/**
* Add a job to the `at` queue
* @param string $command
* @param string $time see `man at`
* @param string $queue a-zA-Z see `man at`
* @return mixed
*/
static private function addCommand($command, $time, $queue = null)
{
$command = self::escape($command);
$time = self::escape($time);
$exec_string = "echo '$command' | " . self::$binary;
if(null !== $queue) {
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
}
$exec_string .= " $time ";
return self::addJob($exec_string);
}
/**
* Add a file job to the `at` queue
* @param string $file Full path to the file to be executed
* @param string $time see `man at`
* @param string $queue a-zA-Z see `man at`
* @return mixed
*/
static private function addFile($file, $time, $queue = null)
{
$file = self::escape($file);
$time = self::escape($time);
$exec_string = self::$binary . ' ' . self::$atSwitches['file'] . " $file";
if(null !== $queue) {
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
}
$exec_string .= " $time ";
return self::addJob($exec_string);
}
/**
* Return a list of the jobs currently in the queue. If you do not specify
* a queue to look at then it will return all jobs in all queues.
* @param string $queue
* @return array of Job objects
* @return mixed
*/
static private function listQueue($queue = null)
{
$exec_string = self::$binary . ' ' . self::$atSwitches['list_queue'];
if(null !== $queue) {
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
}
$result = self::exec($exec_string);
return self::transform($result, 'queue');
}
/**
* Remove a job by job number
* @param int $job_number
* @return Boolean
*/
static public function removeJob($job_number)
{
$rc = true;
if (empty($job_number)) {
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
consoleLog(static::$res, CON_ERROR, $hdr . RES_ATW . ERROR_DATA_INPUT_EMPTY . STRING_JOB_NUMBER);
return(false);
}
$job_number = self::escape($job_number);
// $exec_string = self::$binary . ' ' . self::$atSwitches['remove'] . " $job_number";
$exec_string = 'atrm ' . $job_number;
$output = self::exec($exec_string);
if(count($output)) {
$rc = false;
foreach ($output as $errorMessage) {
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
consoleLog(static::$res, CON_ERROR, $hdr . $errorMessage);
}
echo getDateTime() . CON_ERROR . RES_ATW . $output[0] . PHP_EOL;
}
return($rc);
}
/**
* Add a job to the at queue and return the
* @param string $job_exec_string
* @return mixed
*/
static private function addJob($job_exec_string)
{
$output = self::exec($job_exec_string);
return (count($output) == 1) ? $output[0] : $output[1];
// $job = self::transform($output);
// if(!count($job)) {
// $logger = new gacErrorLogger();
// $logger->warn('failed to add job to the queue. Exec command: ' . $job_exec_string);
// $logger->__destruct();
// }
// return reset($job);
}
/**
* Transform the output of `at` into an array of objects
* @param array $output_array
* @param string $type Is this an add or list we are transforming?
* @return array An array of Job objects
*/
static private function transform(array $output_array, string $type = 'add'):array
{
$jobs = array();
// Get the appropriate regex class property for the type
// of `at` switch/command being run at this point in time.
$regex = $type . 'Regex';
$regex = self::$$regex;
$map = $type .'Map';
$map = self::$$map;
foreach($output_array as $line) {
$matches = array();
@preg_match($regex, $line, $matches);
if(count($matches) > count($map)) {
$jobs[] = self::mapJob($matches, $map);
}
}
return $jobs;
}
/**
* Map the details matched with the regex to descriptively named properties
* in a new Job object
* @param array $details
* @param array $map
* @return Job
*/
static private function mapJob($details, $map)
{
$Job = new Job();
foreach($details as $key => $detail) {
if(isset($map[$key])) {
$Job->$map[$key] = $detail;
}
}
return $Job;
}
/**
* Escape a string that will be passed to exec
* @param string $string
* @return string
*/
static private function escape($string)
{
return escapeshellcmd($string);
}
/**
* Run the command via exec() and return each line of the output as an
* array
* @param string $string
* @return array Each line of output is an element in the array
*/
static private function exec($string)
{
$output = array();
$string .= ' ' . self::$pipeTo;
exec($string, $output);
return $output;
}
}
/**
* A simple class for storing a jobs details and some methods for manipulating
* it. A job model if you will.
*
* @author Simon Holywell <treffynnon@php.net>
* @version 16.11.2010
*/
class Job {
/**
* Data store for the job details
* @var array
*/
public array $data = array();
protected string $res = 'CRON: ';
protected /** @noinspection PhpMissingFieldTypeInspection */ $date;
/**
* Magic method to set a value in the $data
* property of the class
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
$this->data[$name] = $value;
}
/**
* Magic method to get a value in the $data property
* of the class
* @param string $name
* @return mixed
*/
public function __get($name)
{
if (isset($this->data[$name])) {
return $this->data[$name];
}
$logger = new gacErrorLogger();
$trace = debug_backtrace();
$logger->warn("Undefined property via __get(): $name in $trace[0]['file'] . on line $trace[0]['line']");
$logger->__destruct();
return(false);
}
/**
* Magic method to check for the existence of an
* index in the $data property of the class
* @param string $name
* @return bool
*/
public function __isset($name)
{
return isset($this->data[$name]);
}
/**
* Magic method to unset an index in the $data property
* of the class
* @param string $name
*/
public function __unset($name)
{
unset($this->data[$name]);
}
/**
* Remove this job from the queue
*/
public function remove() {
if(isset($this->job_number)) {
gacATWrapper::removeJob((int)$this->job_number);
}
}
/**
* Get a DateTime object for date and time extracted from
* the output of `at`
* @example echo $job->date()->format('d-m-Y');
* @uses DateTime
* @return DateTime A PHP DateTime object
*/
public function date(): ?DateTime
{
try {
return new DateTime($this->date);
} catch (Exception | TypeError $t) {
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
return null;
}
}
}