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:
520
brokers/adminBrokerIn.php
Normal file
520
brokers/adminBrokerIn.php
Normal file
@@ -0,0 +1,520 @@
|
||||
<?php
|
||||
/**
|
||||
* adminBrokerIn.php -- the admin-in broker client
|
||||
*
|
||||
* this broker is part of the administrative-services suite - and is intended to "live" on the admin instance.
|
||||
*
|
||||
* the primary purpose of this broker is to accept incoming system, audit or journaling events. This is a direct
|
||||
* broker (fire-n-forget) that does not publish a response to the event.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 08-16-17 mks CORE-500: cleaned-up some IDE warnings
|
||||
* 08-21-17 mks CORE-500: completed coding for systemEvents->brokerEvents tracking
|
||||
* 02-06-18 mks _INF-139: PHP 7.2 exception handling
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 10-17-18 mks DB-72: audit event coding
|
||||
* 02-11-19 mks DB-100: offloaded a chunk of broker-event code into core for smaller footprint
|
||||
* 09-19-19 mks DB-136: better exception handling, moved log/metric code to respective brokers
|
||||
* fixed console log message where auditIn event always generating error message on success
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
* 09-17-20 mks DB-168: updated service registration, updated exception handling to current standard
|
||||
*
|
||||
*/
|
||||
//use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPChannelClosedException;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
//use PhpAmqpLib\Message\AMQPMessage;
|
||||
//use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'ADMI: ';
|
||||
|
||||
// event management for children
|
||||
$adminServiceConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
||||
$numberChildren = $adminServiceConfig[CONFIG_BROKER_INSTANCES][CONFIG_ADMIN_BROKER_IN];
|
||||
$requestsPerInstance = (empty($adminServiceConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $adminServiceConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(0, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
try {
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
|
||||
$queue = $queueTag . BROKER_QUEUE_AI;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($brokerConnection)) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$childLog->fatal($hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_AI);
|
||||
consoleLog($res, CON_ERROR,$hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_AI);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// $brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
$brokerChannel->queue_declare($queue);
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable | TypeError $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the broker child start-up as a system-event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
consoleLog($res, CON_DEBUG, 'Child GUID: ' . $childGUID);
|
||||
consoleLog($res,CON_DEBUG, 'root GUID: ' . $groot);
|
||||
}
|
||||
|
||||
$requestCounter++;
|
||||
$returnData = null;
|
||||
$eventTimer = false;
|
||||
$request = null;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$thisPid = getmypid();
|
||||
$eventGUID = guid();
|
||||
$ogGUID = '';
|
||||
|
||||
// set-up the call-back logger
|
||||
$callBackLog = new gacErrorLogger($eventGUID, false);
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_AI . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$event = BROKER_QUEUE_AI . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_AI . '(' . $request[BROKER_REQUEST] . ')';
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_AI;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_CREATE :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
// validate that we have a data-template in meta
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
} elseif (!isset($request[BROKER_META_DATA][META_CLIENT]) or $request[BROKER_META_DATA][META_CLIENT] != CLIENT_SYSTEM) {
|
||||
$conMsg = ERROR_BROKER_CLIENT_NOT_AUTH;
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->create($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_UPDATE :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
} elseif (!isset($request[BROKER_META_DATA][META_CLIENT]) or $request[BROKER_META_DATA][META_CLIENT] != CLIENT_SYSTEM) {
|
||||
$conMsg = ERROR_BROKER_CLIENT_NOT_AUTH;
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->update($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_ADMIN_BROKER_EVENT:
|
||||
$eventTimer = true; // set to true if you want to log the processing-time for an event
|
||||
if (!isset($request[BROKER_DATA]) or empty($request[BROKER_DATA])) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} else {
|
||||
if (isset($request[BROKER_META_DATA][META_EVENT_GUID])) {
|
||||
$ogGUID = $request[BROKER_META_DATA][META_EVENT_GUID];
|
||||
}
|
||||
// disable auditing so we don't get into an infinite loop creating a new system event record
|
||||
$metaCopy = $request[BROKER_META_DATA];
|
||||
$metaCopy[META_AUDIT_EVENT] = 1;
|
||||
$tmpObj = new gacSystemEvents($metaCopy);
|
||||
if ($tmpObj->status) {
|
||||
$tmpObj->_createRecord($request[BROKER_DATA]);
|
||||
if ($tmpObj->status) {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_CREATE;
|
||||
$eventSuccess = true;
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_CREATE;
|
||||
}
|
||||
}
|
||||
if (is_object($tmpObj)) $tmpObj->__destruct();
|
||||
unset($tmpObj);
|
||||
}
|
||||
break;
|
||||
|
||||
// DB-72: Audit Event
|
||||
case BROKER_REQUEST_ADMIN_AUDIT_CREATE :
|
||||
$eventTimer = true;
|
||||
$journalData = [];
|
||||
$errorList = [];
|
||||
$haveJournal = false;
|
||||
if (!isset($request[BROKER_DATA]) or empty($request[BROKER_DATA])) {
|
||||
$conMsg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$callBackLog->data($conMsg);
|
||||
} elseif (!isset($request[BROKER_DATA][SYSTEM_EVENT_DATA]) or empty($request[BROKER_DATA][SYSTEM_EVENT_DATA])) {
|
||||
$conMsg = ERROR_DATA_MISSING_ARRAY . SYSTEM_EVENT_DATA;
|
||||
$callBackLog->data($conMsg);
|
||||
} else {
|
||||
try {
|
||||
// instantiate a system event object
|
||||
$objSysEv = new gacSystemEvents($request[BROKER_META_DATA]);
|
||||
if (!$objSysEv->status) {
|
||||
$conMsg = ERROR_TEMPLATE_INSTANTIATE . TEMPLATE_CLASS_SYS_EVENTS;
|
||||
$callBackLog->error($conMsg);
|
||||
} else {
|
||||
$objSysEv->_createRecord([$request[BROKER_DATA][SYSTEM_EVENT_DATA]], DATA_AUDT);
|
||||
unset($request[BROKER_DATA][SYSTEM_EVENT_DATA]);
|
||||
// grab journaling data if it exists and set a flag
|
||||
if (array_key_exists(STRING_JOURNAL_DATA, $request[BROKER_DATA])) {
|
||||
$journalData = $request[BROKER_DATA][STRING_JOURNAL_DATA];
|
||||
unset($request[BROKER_DATA][STRING_JOURNAL_DATA]);
|
||||
$haveJournal = true;
|
||||
}
|
||||
if (!$objSysEv->status) {
|
||||
$conMsg = sprintf(ERROR_DATA_IMPORT, SYSTEM_EVENT_DATA, $objSysEv->class);
|
||||
$callBackLog->data($conMsg);
|
||||
} else {
|
||||
/** @var gacMongoDB $objAudit */
|
||||
if (is_null($objAudit = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$systemEventToken = $objSysEv->getColumn(DB_EVENT_GUID);
|
||||
$rc = $objAudit->launchAudit($request, $haveJournal, $systemEventToken, $journalData);
|
||||
$conMsg = ($rc) ? SUCCESS_AUDIT_EVENT : ERROR_AUDIT_GENERIC_FAIL;
|
||||
if (!$rc and count($objAudit->eventMessages)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_AUDIT_FAIL);
|
||||
foreach ($objAudit->eventMessages as $errorMessage) {
|
||||
consoleLog($res, CON_ERROR, $errorMessage);
|
||||
}
|
||||
} elseif (!$rc) {
|
||||
consoleLog($res, CON_ERROR, ERROR_AUDIT_FAILED);
|
||||
$conMsg = ERROR_AUDIT_FAILED;
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
}
|
||||
if (is_object($objAudit)) $objAudit->__destruct();
|
||||
unset($objAudit);
|
||||
}
|
||||
}
|
||||
if (is_object($objSysEv)) $objSysEv->__destruct();
|
||||
unset($objSysEv);
|
||||
}
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$conMsg = ERROR_TYPE_EXCEPTION;
|
||||
$errorList[] = $conMsg;
|
||||
consoleLog($res, CON_ERROR, $hdr . $conMsg);
|
||||
consoleLog($res, CON_ERROR, $t->getMessage());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_NEW_SESSION :
|
||||
$eventTimer = true;
|
||||
if (!isset($request[BROKER_META_DATA][META_SESSION_GUID]) or empty($request[BROKER_META_DATA][META_SESSION_GUID])) {
|
||||
$conMsg = sprintf(ERROR_META_FIELD_404, META_SESSION_GUID);
|
||||
} elseif (!isset($request[BROKER_DATA][SYSTEM_EVENT_DURATION]) or empty($request[BROKER_DATA][SYSTEM_EVENT_DURATION])) {
|
||||
$conMsg = sprintf(ERROR_DATA_KEY_404 . SYSTEM_EVENT_DURATION);
|
||||
} elseif (!validateGUID($request[BROKER_META_DATA][META_SESSION_GUID])) {
|
||||
$conMsg = ERROR_INVALID_GUID . $request[BROKER_META_DATA][META_SESSION_GUID];
|
||||
} else {
|
||||
$sessionToken = $request[BROKER_META_DATA][META_SESSION_GUID];
|
||||
$duration = intval($request[BROKER_DATA][SYSTEM_EVENT_DURATION]);
|
||||
$rc = gasStatic::createATJob($duration, $sessionToken);
|
||||
if (!is_null($rc)) {
|
||||
// we successfully created the AT(1) job - update the sys-event record
|
||||
$tmpObj = new gacSystemEvents($request[BROKER_META_DATA]);
|
||||
if (!$tmpObj->status) {
|
||||
$conMsg = ERROR_TEMPLATE_INSTANTIATE . $request[BROKER_META_DATA][META_TEMPLATE];
|
||||
} else {
|
||||
// fetch the system event record
|
||||
$tmpObj->fetchRecordBySessionGUID($sessionToken);
|
||||
if ($tmpObj->status) {
|
||||
// update the system-event record with the AT results
|
||||
$query = [SYSTEM_EVENT_FK_SESSION_GUID => [OPERAND_NULL => [OPERATOR_EQ => [$tmpObj->getColumn(SYSTEM_EVENT_FK_SESSION_GUID)]]]];
|
||||
$update = [SYSTEM_EVENT_AT_RESULTS => $rc];
|
||||
$data = [ STRING_QUERY_DATA => $query, STRING_UPDATE_DATA => $update ];
|
||||
$tmpObj->_updateRecord($data);
|
||||
if ($tmpObj->status) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
} else {
|
||||
$callBackLog->warn(ERROR_MDB_SYS_EVENT_UPDATE);
|
||||
consoleLog($res, CON_SYSTEM, ERROR_MDB_SYS_EVENT_UPDATE);
|
||||
}
|
||||
} else {
|
||||
$callBackLog->warn(ERROR_MDB_SYS_EVENT_SAVE);
|
||||
consoleLog($res, CON_SYSTEM, ERROR_MDB_SYS_EVENT_SAVE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$callBackLog->warn(ERROR_AT_SAVE);
|
||||
consoleLog($res, CON_SYSTEM, ERROR_AT_SAVE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_ADMIN_CACHE_SMASH :
|
||||
$eventTimer = true;
|
||||
$errors = [];
|
||||
if (!isset($request[BROKER_DATA]) or empty($request[BROKER_DATA])) {
|
||||
$conMsg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$callBackLog->data($conMsg);
|
||||
} else {
|
||||
try {
|
||||
// calls the cache-smash method and passes the list of guids
|
||||
if (!gasCache::smashCache($request[BROKER_DATA][STRING_DATA], $errors))
|
||||
consoleLog($res, CON_ERROR, ERROR_CACHE_SMASH_FAIL_USER);
|
||||
else
|
||||
consoleLog($res, CON_SUCCESS, SUCCESS_CACHE_SMASH);
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$conMsg = ERROR_TYPE_EXCEPTION;
|
||||
$errorList[] = $conMsg;
|
||||
consoleLog($res, CON_ERROR, $hdr . $conMsg);
|
||||
consoleLog($res, CON_ERROR, $t->getMessage());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$conMsg = ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST];
|
||||
$callBackLog->warn(ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST]);
|
||||
// todo - not a supported event so log something dire
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = ERROR_FINE_PICKLE;
|
||||
}
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
|
||||
// log a system-event for the event -- unlike the other system events, we're not going to submit
|
||||
// this one via a broker - which is standard but, instead, we're going to write the record out
|
||||
// directly since doing otherwise would cause an infinite loop in processing.
|
||||
if ($eventTime and $eventTimer) {
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($ogGUID)) $data[SYSTEM_EVENT_OGUID] = $ogGUID;
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
gasCache::sysDel(($groot . UDASH . $thisPid));
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_AI, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_consume($queue, '', false, true, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (AMQPChannelClosedException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_AI));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
583
brokers/adminBrokerOut.php
Normal file
583
brokers/adminBrokerOut.php
Normal file
@@ -0,0 +1,583 @@
|
||||
<?php
|
||||
/**
|
||||
* adminBrokerOut.php
|
||||
*
|
||||
* This is the admin-out broker and is, currently, a placeholder for future work.
|
||||
*
|
||||
* This broker is intended to be used to fetch data/reports from the admin-side. As it stands today, only base
|
||||
* events are supported.
|
||||
*
|
||||
* This broker is pretty old requires refactoring to bring up-to standards. As it is now, it is simply a placeholder
|
||||
* service.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 08-24-17 mks CORE-500: broker events
|
||||
* 02-06-18 mks _INF-139: migration event coding, PHP 7.2 exception handling
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 06-07-18 mks CORE-1013: remote fetch event added
|
||||
* 07-09-18 mks CORE-1017: pedigree fetch event added
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$res = 'ADMO: ';
|
||||
// event management for children
|
||||
$adminServiceConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
||||
$numberChildren = $adminServiceConfig[CONFIG_BROKER_INSTANCES][CONFIG_ADMIN_BROKER_OUT];
|
||||
$requestsPerInstance = (empty($adminServiceConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $adminServiceConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $groot;
|
||||
// $startingMemory = memory_get_usage(true);
|
||||
// todo -- when this broker becomes active, add the systemEvent for calculating memory consumption on SIGCLD
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
try {
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
$queue = $queueTag . BROKER_QUEUE_AO;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($brokerConnection)) {
|
||||
$parentLog->fatal(ERROR_RESOURCE_404 . RESOURCE_ADMIN);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_ADMIN);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable | TypeError $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
$errorList = array();
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event = BROKER_QUEUE_AO . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $msg, null, null]);
|
||||
$event = BROKER_QUEUE_AO . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_AO . '(' . $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) consoleLog($res, CON_ERROR, ERROR_BROKER_REQUEST_BAD . BROKER_REQUEST);
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_AO;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_AO), null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PEDIGREE :
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_PEDIGREE;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, gasConfig::getPedigree()]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_ADMIN_MWH_EVENT_CREATE :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
if (!isset($request[BROKER_META_DATA][META_CLIENT])) {
|
||||
$msg = ERROR_META_CLIENT_404;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} elseif ($request[BROKER_META_DATA][META_CLIENT] != CLIENT_SYSTEM) {
|
||||
$msg = ERROR_BROKER_CLIENT_NOT_AUTH . COLON . $request[BROKER_META_DATA][META_CLIENT];
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} elseif ($request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_MIGRATIONS
|
||||
and $request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_WAREHOUSE) {
|
||||
$msg = ERROR_TEMPLATE_WRONG;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
} else {
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$widget->_createRecord($request[BROKER_DATA]);
|
||||
if (!$widget->status) {
|
||||
$msg = FAIL_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_CREATE;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
$aryRetData = buildReturnPayload([false, $widget->state, $widget->eventMessages, null]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_CREATE;
|
||||
$aryRetData = buildReturnPayload([true, $widget->state, $widget->eventMessages, $widget->getData()]);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_ADMIN_MWH_EVENT_FETCH :
|
||||
$eventTimer = true;
|
||||
// try { // if debugging, turn on the exception trapper
|
||||
$errors = [];
|
||||
if (empty($request[BROKER_DATA]) or !is_array($request[BROKER_DATA])) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . BROKER_DATA;
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $msg]);
|
||||
} elseif (!array_key_exists(META_TEMPLATE, $request[BROKER_META_DATA])
|
||||
or ($request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_MIGRATIONS
|
||||
and $request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_WAREHOUSE)) {
|
||||
$msg = sprintf(ERROR_TEMPLATE_BAD, TEMPLATE_CLASS_MIGRATIONS);
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $msg, null]);
|
||||
} else {
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$widget->_fetchRecords($request[BROKER_DATA]);
|
||||
if (!$widget->status) {
|
||||
// fetch failed
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_FETCH;
|
||||
$aryRetData = buildReturnPayload([false, $widget->state, $widget->eventMessages, null]);
|
||||
} else {
|
||||
// update successful
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_FETCH;
|
||||
// ReturnPayload - a query that returns no data will show success - eval the return
|
||||
// state and return either a "no data found" message or the query
|
||||
// results to the calling client
|
||||
$rp = ($widget->state == STATE_NOT_FOUND) ? $widget->eventMessages : $widget->queryResults;
|
||||
$aryRetData = buildReturnPayload([true, $widget->state, $rp, $widget->getData()]);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
}
|
||||
// } catch (Throwable | TypeError $t) {
|
||||
// $eLine = $t->getLine();
|
||||
// $eFile = $t->getFile();
|
||||
// $eMsg = $t->getMessage();
|
||||
// $msg = $eFile . COLON_NS . $eLine . COLON . $eMsg;
|
||||
// consoleLog($res, CON_ERROR, $msg);
|
||||
// $conMsg = $hdrConE . FAIL_EVENT . BROKER_REQUEST_ADMIN_MIGRATE_FETCH_EVENT;
|
||||
// $aryRetData = buildReturnPayload([false, STATE_FAIL, $eMsg, null]);
|
||||
// }
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_REMOTE_FETCH :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$widget->_fetchRecords($request[BROKER_DATA]);
|
||||
if ($widget->status) {
|
||||
$eventSuccess = true;
|
||||
$widget->eventMessages[] = STRING_REC_COUNT_RET . $widget->recordsReturned;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_FETCH;
|
||||
$queryMeta = [
|
||||
STRING_REC_COUNT_RET => $widget->recordsReturned,
|
||||
STRING_REC_COUNT_TOT => $widget->recordsInCollection
|
||||
];
|
||||
// recordsInQuery is a PDO thing so let's see if it exists in the class object
|
||||
if (isset($widget->recordsInQuery) and $widget->recordsInQuery) {
|
||||
$queryMeta[STRING_REC_COUNT_QUERY] = $widget->recordsInQuery;
|
||||
}
|
||||
if (isset($request[BROKER_META_DATA][META_DONUT_FILTER]) and $request[BROKER_META_DATA][META_DONUT_FILTER] == 1) {
|
||||
$queryResults = $widget->getData();
|
||||
} elseif ($widget->useCache or (isset($request[BROKER_META_DATA][META_DO_CACHE]) and $request[BROKER_META_DATA][META_DO_CACHE])) {
|
||||
$queryResults = $widget->getCK();
|
||||
} else {
|
||||
$queryResults = $widget->getData();
|
||||
}
|
||||
$retData = [STRING_QUERY_RESULTS => $queryResults, STRING_QUERY_DATA => $queryMeta];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $widget->eventMessages, $retData]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_FETCH;
|
||||
$aryRetData = buildReturnPayload([false, $widget->state, $widget->eventMessages, null]);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_AUDIT_RESTORE :
|
||||
$eventTimer = true;
|
||||
$errors = [];
|
||||
if (!isset($request[BROKER_DATA]) or empty($request[BROKER_DATA])) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
$errors[] = $msg;
|
||||
} elseif (!is_array($request[BROKER_DATA])) {
|
||||
$msg = ERROR_DATA_ARRAY_NOT_ARRAY . STRING_DATA;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
$errors[] = $msg;
|
||||
} elseif (!isset($request[BROKER_DATA][STRING_KEY])) {
|
||||
$msg = ERROR_ARRAY_KEY_404 . BROKER_DATA . COLON . STRING_KEY;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
$errors[] = $msg;
|
||||
} else {
|
||||
$key = $request[BROKER_DATA][STRING_KEY];
|
||||
if (!validateGUID($key)) {
|
||||
$msg = ERROR_INVALID_GUID . $key;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
$errors[] = $msg;
|
||||
} else {
|
||||
// inject a key into the metaPayload to flag all requests as audit requests
|
||||
$request[BROKER_META_DATA][META_AUDIT_EVENT] = 1;
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($request[BROKER_META_DATA], $key, $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
try {
|
||||
$data = []; // for the return payload containing original and changed records
|
||||
$rc = $widget->restoreAuditRecord($data);
|
||||
switch ($rc) {
|
||||
case true :
|
||||
$eventSuccess = true;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $widget->eventMessages, SUCCESS_DB_RECORD_RESTORED]);
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_AUDIT_RESTORE;
|
||||
break;
|
||||
case false :
|
||||
default :
|
||||
if (!empty($errors)) $widget->eventMessages = array_merge($widget->eventMessages, $errors);
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_AUDIT_RESTORE;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, $widget->eventMessages, null]);
|
||||
break;
|
||||
}
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$msg = ERROR_TYPE_EXCEPTION . $t->getMessage();
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_ADMIN_MWH_EVENT_UPDATE :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
if (!isset($request[BROKER_DATA]) or empty($request[BROKER_DATA])) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} elseif (!isset($request[BROKER_META_DATA][META_CLIENT])) {
|
||||
$msg = ERROR_META_CLIENT_404;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} elseif ($request[BROKER_META_DATA][META_CLIENT] != CLIENT_SYSTEM) {
|
||||
$msg = ERROR_BROKER_CLIENT_NOT_AUTH . COLON . $request[BROKER_META_DATA][META_CLIENT];
|
||||
$conMsg = $msg;
|
||||
$callBackLog->data($msg);
|
||||
} elseif ($request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_MIGRATIONS
|
||||
and $request[BROKER_META_DATA][META_TEMPLATE] != TEMPLATE_CLASS_WAREHOUSE) {
|
||||
$msg = ERROR_TEMPLATE_WRONG;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
} else {
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$widget->_updateRecord($request[BROKER_DATA]);
|
||||
if (!$widget->status) {
|
||||
$msg = FAIL_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_UPDATE;
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
$aryRetData = buildReturnPayload([false, $widget->state, $widget->eventMessages, null]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_ADMIN_MWH_EVENT_UPDATE;
|
||||
$aryRetData = buildReturnPayload([true, $widget->state, $widget->eventMessages, $widget->getData()]);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
unset($aryRetData[PAYLOAD_CM]);
|
||||
}
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_AO . ' - ' . $msg;
|
||||
$errorList = (empty($errors)) ? null : $errors;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $msg, $errorList]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
// prepare the return payload...
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
} catch (PhpAmqpLib\Exception\AMQPTimeoutException |
|
||||
PhpAmqpLib\Exception\AMQPRuntimeException |
|
||||
Throwable $e) {
|
||||
$logMsg = ERROR_BROKER_EXCEPTION . $e->getMessage();
|
||||
$callBackLog->fatal($logMsg);
|
||||
consoleLog($res, CON_ERROR, $logMsg);
|
||||
}
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
if (!$eventSuccess) {
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_reject($_request->delivery_info[BROKER_DELIVERY_TAG], false);
|
||||
} else {
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
}
|
||||
unset($msg);
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_AO, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_AO));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
352
brokers/adminGraphBroker.php
Normal file
352
brokers/adminGraphBroker.php
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
/**
|
||||
* admionGraphBroker.php -- the Graph (grafana) broker client
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-16-19 mks DB-113: original coding
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
//use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
|
||||
//use PhpAmqpLib\Message\AMQPMessage;
|
||||
//use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
// load the lite version of the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'GRPH: ';
|
||||
|
||||
// event management for children
|
||||
$graphServiceConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
||||
$numberChildren = $graphServiceConfig[CONFIG_BROKER_INSTANCES][CONFIG_GRAPH_BROKER];
|
||||
$requestsPerInstance = (empty($graphServiceConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $graphServiceConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(0, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
try {
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
|
||||
$queue = $queueTag . BROKER_QUEUE_GRAPHS;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($brokerConnection)) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$childLog->fatal($hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_GRAPHS);
|
||||
consoleLog($res, CON_ERROR,$hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_GRAPHS);
|
||||
exit(SHELL_FAILURE); // shell-script exit value for fail
|
||||
}
|
||||
|
||||
// declare the channel...
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// declare the topic exchange for topic-logging
|
||||
$brokerChannel->exchange_declare(EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_TYPE_TOPIC, false, false, false);
|
||||
// declare the channel queue and create the queue name
|
||||
list($queueName, ,) = $brokerChannel->queue_declare($queue);
|
||||
// this broker handles all messages passed to the topic_logs exchange
|
||||
$brokerChannel->queue_bind($queueName, EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_QUEUE_BINDING_METRICS);
|
||||
} catch (AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(SHELL_FAILURE);
|
||||
}
|
||||
|
||||
// register the broker child start-up as a system-event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
consoleLog($res, CON_DEBUG, 'Child GUID: ' . $childGUID);
|
||||
consoleLog($res,CON_DEBUG, 'root GUID: ' . $groot);
|
||||
}
|
||||
|
||||
$requestCounter++;
|
||||
$returnData = null;
|
||||
$eventTimer = false;
|
||||
$request = null;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$thisPid = getmypid();
|
||||
$eventGUID = guid();
|
||||
$ogGUID = '';
|
||||
|
||||
// set-up the call-back logger
|
||||
$callBackLog = new gacErrorLogger($eventGUID, false);
|
||||
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_GRAPHS . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$event = BROKER_QUEUE_GRAPHS . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_GRAPHS . '(' . $request[BROKER_REQUEST] . ')';
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_GRAPHS;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// standard query-metrics event that is also handled in-parallel by LogsBroker is now:
|
||||
case BROKER_REQUEST_MET :
|
||||
if (empty($request[BROKER_DATA])) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$msg = ERROR_DATA_404;
|
||||
consoleLog($res, CON_ERROR, $hdr . $msg);
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_MET;
|
||||
} else {
|
||||
$meta = $request[BROKER_META_DATA];
|
||||
$meta[META_TEMPLATE] = TEMPLATE_CLASS_GRAPHS;
|
||||
$meta[META_SKIP_AUDIT] = 1;
|
||||
$meta[META_CLIENT] = CLIENT_SYSTEM;
|
||||
try {
|
||||
/** @var gacMongoDB $objGraphs */
|
||||
if (is_null($objGraphs = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
if ($objGraphs->processMetricsForGraph($request[BROKER_DATA])) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_MET . INFO_GRAPH_VERSION;
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_MET;
|
||||
}
|
||||
}
|
||||
if (is_object($objGraphs)) $objGraphs->__destruct();
|
||||
unset($objGraphs);
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
$conMsg = ERROR_EXCEPTION;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$conMsg = ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST];
|
||||
$callBackLog->warn(ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST]);
|
||||
// todo - not a supported event so log something dire
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = ERROR_FINE_PICKLE;
|
||||
}
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
|
||||
// log a system-event for the event -- unlike the other system events, we're not going to submit
|
||||
// this one via a broker - which is standard but, instead, we're going to write the record out
|
||||
// directly since doing otherwise would cause an infinite loop in processing.
|
||||
if ($eventTime and $eventTimer) {
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($ogGUID)) $data[SYSTEM_EVENT_OGUID] = $ogGUID;
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
gasCache::sysDel(($groot . UDASH . $thisPid));
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_GRAPHS, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_consume($queue, '', false, true, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_GRAPHS));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
342
brokers/adminLogsBroker.php
Normal file
342
brokers/adminLogsBroker.php
Normal file
@@ -0,0 +1,342 @@
|
||||
<?php
|
||||
/**
|
||||
* adminSyslogBroker.php -- the syslog broker client
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-16-19 mks DB-113: original coding
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
//use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
|
||||
//use PhpAmqpLib\Message\AMQPMessage;
|
||||
//use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
// load the lite version of the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'LOGS: ';
|
||||
|
||||
// event management for children
|
||||
$syslogServiceConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
||||
$numberChildren = $syslogServiceConfig[CONFIG_BROKER_INSTANCES][CONFIG_LOG_BROKER];
|
||||
$requestsPerInstance = (empty($syslogServiceConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $syslogServiceConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(0, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
try {
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
// $exchange = BROKER_EXCHANGE_A1;
|
||||
|
||||
$queue = $queueTag . BROKER_QUEUE_LOGS;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($brokerConnection)) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$childLog->fatal($hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_LOGS);
|
||||
consoleLog($res, CON_ERROR,$hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_LOGS);
|
||||
exit(SHELL_FAILURE); // shell-script exit value for fail
|
||||
}
|
||||
|
||||
// declare the channel...
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// declare the topic exchange for topic-logging
|
||||
$brokerChannel->exchange_declare(EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_TYPE_TOPIC, false, false, false);
|
||||
// declare the channel queue and create the queue name
|
||||
list($queueName, ,) = $brokerChannel->queue_declare($queue);
|
||||
// this broker handles all messages passed to the topic_logs exchange (LOGS and METRICS)
|
||||
$brokerChannel->queue_bind($queueName, EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_QUEUE_BINDING_ALL);
|
||||
} catch (AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(SHELL_FAILURE);
|
||||
}
|
||||
|
||||
// register the broker child start-up as a system-event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
consoleLog($res, CON_DEBUG, 'Child GUID: ' . $childGUID);
|
||||
consoleLog($res,CON_DEBUG, 'root GUID: ' . $groot);
|
||||
}
|
||||
|
||||
$requestCounter++;
|
||||
$returnData = null;
|
||||
$eventTimer = false;
|
||||
$request = null;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$thisPid = getmypid();
|
||||
$eventGUID = guid();
|
||||
$ogGUID = '';
|
||||
|
||||
// set-up the call-back (relative to the broker) logger
|
||||
$callBackLog = new gacErrorLogger($eventGUID, false);
|
||||
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_SYSLOG . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$event = BROKER_QUEUE_LOGS . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_LOGS . '(' . $request[BROKER_REQUEST] . ')';
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
// /** @noinspection PhpUndefinedFieldInspection PhpUndefinedMethodInspection */
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_SYSLOG;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_LOG :
|
||||
$callBackLog->errStack = $request[BROKER_DATA];
|
||||
$callBackLog->writeLogMessage();
|
||||
if ($callBackLog->status) {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_LOG;
|
||||
$eventSuccess = true;
|
||||
} else {
|
||||
$conMsg = basename(__FILE__) . COLON_NS . __LINE__ . COLON . FAIL_EVENT . BROKER_REQUEST_LOG;
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_MET :
|
||||
$callBackLog->errStack = $request[BROKER_DATA];
|
||||
$callBackLog->writeLogMessage(true);
|
||||
if ($callBackLog->status) {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_MET;
|
||||
$eventSuccess = true;
|
||||
} else {
|
||||
$conMsg = basename(__FILE__) . COLON_NS . __LINE__ . COLON . FAIL_EVENT . BROKER_REQUEST_MET;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$conMsg = ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST];
|
||||
$callBackLog->warn(ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST]);
|
||||
// todo - not a supported event so log something dire
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = ERROR_FINE_PICKLE;
|
||||
}
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
// /** @noinspection PhpUndefinedFieldInspection PhpUndefinedMethodInspection */
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
|
||||
// log a system-event for the event -- unlike the other system events, we're not going to submit
|
||||
// this one via a broker - which is standard but, instead, we're going to write the record out
|
||||
// directly since doing otherwise would cause an infinite loop in processing.
|
||||
if ($eventTime and $eventTimer) {
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($ogGUID)) $data[SYSTEM_EVENT_OGUID] = $ogGUID;
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
gasCache::sysDel(($groot . UDASH . $thisPid));
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_SYSLOG, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_consume($queue, '', false, true, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_SYSLOG));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
335
brokers/adminSyslogBroker.php
Normal file
335
brokers/adminSyslogBroker.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
/**
|
||||
* adminSyslogBroker.php -- the syslog broker client
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-16-19 mks DB-113: original coding
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
//use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
|
||||
//use PhpAmqpLib\Message\AMQPMessage;
|
||||
//use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
// load the lite version of the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'SYSL: ';
|
||||
|
||||
// event management for children
|
||||
$syslogServiceConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
||||
$numberChildren = $syslogServiceConfig[CONFIG_BROKER_INSTANCES][CONFIG_SYSLOG_BROKER];
|
||||
$requestsPerInstance = (empty($syslogServiceConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $syslogServiceConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(0, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
try {
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
|
||||
$queue = $queueTag . BROKER_QUEUE_SYSLOG;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($brokerConnection)) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$childLog->fatal($hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_SYSLOG);
|
||||
consoleLog($res, CON_ERROR,$hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN . COLON . BROKER_QUEUE_SYSLOG);
|
||||
exit(SHELL_FAILURE); // shell-script exit value for fail
|
||||
}
|
||||
|
||||
// declare the channel...
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// declare the topic exchange for topic-logging
|
||||
$brokerChannel->exchange_declare(EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_TYPE_TOPIC, false, false, false);
|
||||
// declare the channel queue and create the queue name
|
||||
list($queueName, ,) = $brokerChannel->queue_declare($queue);
|
||||
// this broker handles all messages passed to the topic_logs exchange
|
||||
$brokerChannel->queue_bind($queueName, EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_QUEUE_BINDING_LOGS);
|
||||
} catch (AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(SHELL_FAILURE);
|
||||
}
|
||||
|
||||
// register the broker child start-up as a system-event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
consoleLog($res, CON_DEBUG, 'Child GUID: ' . $childGUID);
|
||||
consoleLog($res,CON_DEBUG, 'root GUID: ' . $groot);
|
||||
}
|
||||
|
||||
$requestCounter++;
|
||||
$returnData = null;
|
||||
$eventTimer = false;
|
||||
$request = null;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$thisPid = getmypid();
|
||||
$eventGUID = guid();
|
||||
$ogGUID = '';
|
||||
|
||||
// set-up the call-back logger
|
||||
$callBackLog = new gacErrorLogger($eventGUID, false);
|
||||
|
||||
if (!firstPassPayloadValidation($_request, $service,$msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_SYSLOG . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$event = BROKER_QUEUE_SYSLOG . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_SYSLOG . '(' . $request[BROKER_REQUEST] . ')';
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_SYSLOG;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// syslog processing happens here
|
||||
case BROKER_REQUEST_LOG :
|
||||
try {
|
||||
$namaste = '[' . CONFIG_ID_NODE_NAMASTE . '] ';
|
||||
$sysLogError = gasStatic::getSysLogError($request[BROKER_DATA][0][(LOG_VALUE . COLLECTION_MONGO_LOGS_EXT)]);
|
||||
if (!syslog($sysLogError, $namaste . $request[BROKER_DATA][0][ERROR_MESSAGE . COLLECTION_MONGO_LOGS_EXT])) {
|
||||
consoleLog($res, CON_ERROR, ERROR_SYSLOG);
|
||||
$conMsg = FAIL_EVENT . ERROR_SYSLOG;
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_SYSLOG;
|
||||
$eventSuccess = true;
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
consoleLog($res, CON_ERROR, $hdr . $t->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$conMsg = ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST];
|
||||
$callBackLog->warn(ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST]);
|
||||
// todo - not a supported event so log something dire
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = ERROR_FINE_PICKLE;
|
||||
}
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
|
||||
// log a system-event for the event -- unlike the other system events, we're not going to submit
|
||||
// this one via a broker - which is standard but, instead, we're going to write the record out
|
||||
// directly since doing otherwise would cause an infinite loop in processing.
|
||||
if ($eventTime and $eventTimer) {
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($ogGUID)) $data[SYSTEM_EVENT_OGUID] = $ogGUID;
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
gasCache::sysDel(($groot . UDASH . $thisPid));
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_SYSLOG, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_consume($queue, '', false, true, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_SYSLOG));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
381
brokers/brokerTemplate.txt
Normal file
381
brokers/brokerTemplate.txt
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
/**
|
||||
* brokerTemplate.txt
|
||||
*
|
||||
* This is the template file for brokers. It holds all the PHP code to create a new broker client/service - all you
|
||||
* need to do is configure the broker instance to be unique to all the other already-existing brokers, and to add
|
||||
* the event handlers.
|
||||
*
|
||||
* Speaking of, the template comes with the default event handlers for ping and shutdown. Comments, such as this one,
|
||||
* are added to key places in the code to alert you to lines that should be modified and suggestions, where possible
|
||||
* for the range of inputs available.
|
||||
*
|
||||
* Please observe the Namaste coding standards when adding comments and comment blocks as your comments will be used
|
||||
* to create Namaste system documentation for other programmers.
|
||||
*
|
||||
* @author mike@givingassistant.org <--- todo change/update to your email
|
||||
* @version 1.0 <--- todo in what namaste version did this module first appear?
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-28-20 mks DB-144: original coding
|
||||
*
|
||||
*/
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Channel\AMQPChannel;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'XXXX: '; // todo <-- change this 4-char field to something unique for the console log
|
||||
|
||||
// todo ------------------------------------------------------------------------------------------------------------------------------------
|
||||
// todo -- if your broker requires it's own configuration section (example here uses the migration section, then
|
||||
// todo -- you'll need to add a relevant section to the XML configuration -- otherwise, delete this section
|
||||
// before we do anything, ensure we have a "migration" section in the configuration
|
||||
if (!array_key_exists(CONFIG_MIGRATION, gasConfig::$settings) // todo <--- change CONFIG_MIGRATION
|
||||
or empty(gasConfig::$settings[CONFIG_MIGRATION]) // todo <--- change CONFIG_MIGRATION
|
||||
or !is_array(gasConfig::$settings[CONFIG_MIGRATION])) { // todo <--- change CONFIG_MIGRATION
|
||||
// XML config for migration is not loaded or is empty or malformed - exit immediately
|
||||
consoleLog($res, CON_SYSTEM, ERROR_CONFIG_RESOURCE_404 . STRING_MIGRATION_CONFIG); // todo <--- change STRING_MIGRATION_CONFIG
|
||||
exit(1);
|
||||
}
|
||||
// todo ------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
// event management for children
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER]; // todo <--- change CONFIG_BROKER_APPSERVER
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_M_BROKER]; // todo <--- change CONFIG_BROKER_M_BROKER
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// todo - validate the broker environment as declared in the XML config
|
||||
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_PRIME; // todo <--- change the environment
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_ADMIN;
|
||||
|
||||
if (!registerService($service)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $startingMemory, $myRequestsPerInstance, $groot;
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
$queue = $queueTag . BROKER_QUEUE_TBD; // todo <--- change BROKER_QUEUE_TBD
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_BROKER);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
try {
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $e) {
|
||||
$childLog->fatal($e->getMessage());
|
||||
consoleLog($res, CON_ERROR, ERROR_BROKER_QUEUE_DECLARE . $queue);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postBrokerEvent($data, $childGUID, $childLog);
|
||||
// todo -- add a broker name to this event so we know which broker is registering
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
$_request[STRING_SERVICE] = $service;
|
||||
$event = BROKER_QUEUE_TBD . '('; // todo <--- change BROKER_QUEUE_TBD
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$errorStack = [];
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
try {
|
||||
if (!firstPassPayloadValidation($_request, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event .= ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorStack)) {
|
||||
for ($index = 0, $last = count($errorStack); $index < $last; $index++) {
|
||||
$conMsg .= $errorStack[$index] . $eos;
|
||||
$callBackLog->error($errorStack[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorStack, null, null]);
|
||||
$event .= ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event .= $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_REQUEST_404);
|
||||
}
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
/** @noinspection PhpUndefinedFieldInspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_TBD; // todo <--- change BROKER_QUEUE_TBD
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_TBD), null]); // todo <--- change BROKER_QUEUE_M
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// todo <--- your events for this broker start here
|
||||
|
||||
default :
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, $msg, null]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
consoleLog($res, CON_SYSTEM, $t->getMessage());
|
||||
$callBackLog->fatal($t->getMessage());
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $t->getMessage(), $errorStack]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_M . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
|
||||
// prepare the return payload...
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
} catch (PhpAmqpLib\Exception\AMQPTimeoutException |
|
||||
PhpAmqpLib\Exception\AMQPRuntimeException |
|
||||
Throwable $e) {
|
||||
$logMsg = ERROR_BROKER_EXCEPTION . $e->getMessage();
|
||||
$callBackLog->fatal($logMsg);
|
||||
consoleLog($res, CON_ERROR, $logMsg);
|
||||
}
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
// todo: core-452: publish the event payload to the sysEvent broker to capture the failed event
|
||||
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
unset($msg);
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postBrokerEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postBrokerEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_TBD, $thisPid, $myRequestsPerInstance)); // todo <--- change BROKER_QUEUE_TBD
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
$brokerChannel->wait();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
; // does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_TBD)); // todo <--- change BROKER_QUEUE_TBD
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postBrokerEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
489
brokers/cBroker.php
Normal file
489
brokers/cBroker.php
Normal file
@@ -0,0 +1,489 @@
|
||||
<?php
|
||||
/**
|
||||
* cBroker.php
|
||||
*
|
||||
* cBroker is the CONS-Broker (consolidated access list) a list provided by the US Treasury Department listing all
|
||||
* individuals and entities who have been blocked from receiving payment for reasons of national security.
|
||||
*
|
||||
* This is a segundo broker and provides the following functionality:
|
||||
*
|
||||
* 1. Event to upload the CONS XML file
|
||||
* 2. Event to process the CONS XML file (stores the XML file into a mongo collection)
|
||||
* 3. Queries against the CONS XML file (which are really queries against the collection created above)
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-07-20 mks DB-180: Original coding
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework environment
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'CONS: '; // CONSolidated access list
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
// event management for children
|
||||
$serviceSettings = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_SEGUNDO];
|
||||
$numberChildren = $serviceSettings[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_C_BROKER];
|
||||
$requestsPerInstance = (empty($serviceSettings[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $serviceSettings[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_NUM_CHILD, substr(basename(__FILE__), 0, -4), $numberChildren));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// todo - validate the broker environment as declared in the XML config
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_SEGUNDO;
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_SEGUNDO;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $startingMemory, $myRequestsPerInstance, $groot, $file;
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
try {
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queue = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG] . BROKER_QUEUE_C;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_SEGUNDO);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_SEGUNDO . COLON . BROKER_QUEUE_C);
|
||||
consoleLog($res, CON_ERROR . ERROR_RESOURCE_404 . RESOURCE_SEGUNDO . COLON . BROKER_QUEUE_C);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
$postNormalResponse = true;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service, $file;
|
||||
$event = BROKER_QUEUE_M . '(';
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$errorStack = [];
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
try {
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event .= ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorStack)) {
|
||||
for ($index = 0, $last = count($errorStack); $index < $last; $index++) {
|
||||
$conMsg .= $errorStack[$index] . $eos;
|
||||
$callBackLog->error($errorStack[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorStack, null, null]);
|
||||
$event .= ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event .= $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_REQUEST_404);
|
||||
}
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_WH;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_WH), null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PEDIGREE :
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_PEDIGREE;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, gasConfig::getPedigree()]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_WAREHOUSE :
|
||||
$eventSuccess = false;
|
||||
$eventTimer = false;
|
||||
|
||||
$objMigrate = new gacMigrations($request[BROKER_DATA], $request[BROKER_META_DATA], EVENT_WAREHOUSE);
|
||||
if (!$objMigrate->status) {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([false, $objMigrate->state, $objMigrate->errorStack, null]);
|
||||
} else {
|
||||
$guid = $objMigrate->objWarehouseMeta->getColumn(DB_TOKEN);
|
||||
// validate return guid
|
||||
if (!validateGUID($guid)) {
|
||||
$conMsg = ERROR_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([ false, FAIL_EVENT, $objMigrate->errorStack, ERROR_BROKER_REQUEST_FAILED]);
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([true, SUCCESS_EVENT, $objMigrate->errorStack, $guid]);
|
||||
$eventSuccess = true;
|
||||
}
|
||||
// send the guid back to the calling client now so we can resume the warehousing...
|
||||
postResponse($aryRetData, $_request, $callBackLog, $res);
|
||||
$postNormalResponse = false;
|
||||
|
||||
// dive back into the objMigration class and perform the warehouse request
|
||||
if (!$objMigrate->whData()) {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$eventSuccess = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_CONS :
|
||||
$lastUpdated = '';
|
||||
$recordCount = 0;
|
||||
$eventTimer = true;
|
||||
$errors = [];
|
||||
$request[BROKER_META_DATA][META_LIMIT_OVERRIDE] = 1;
|
||||
/** @var gacMongoDB $tmpObj */
|
||||
if (is_null($tmpObj = grabWidget($request[BROKER_META_DATA], '', $errors))) {
|
||||
// failed to instantiate the CONS data class object
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_WARNING, $errors, null]);
|
||||
} else {
|
||||
if (is_null($newFileName = $tmpObj->template->saveCONSList($request[BROKER_DATA], $errors))) {
|
||||
// failed to save the CONS list to the tmp directory
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
$aryRetData = buildReturnPayload([FALSE, STATE_FAIL, $errors, null]);
|
||||
} else {
|
||||
if (is_null($aryData = $tmpObj->template->processCONSList($newFileName, $errors, $lastUpdated, $recordCount))) {
|
||||
// failed to process the xml file into a data structure
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
$aryRetData = buildReturnPayload([FALSE, STATE_FAIL, $errors, null]);
|
||||
} else {
|
||||
$tmpObj->_createRecord($aryData, DATA_CONS);
|
||||
if (!$tmpObj->status) {
|
||||
// failed to save CONS data structure to mongo table
|
||||
if (empty($tmpObj->eventMessages))
|
||||
$tmpObj->eventMessages[] = ERROR_SAVE_XML_FILE . STRING_DBR;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, $tmpObj->eventMessages, null]);
|
||||
} else {
|
||||
if ($tmpObj->count != $recordCount) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
$msg = sprintf(ERROR_DATA_RECORD_COUNT, $recordCount, $tmpObj->count);
|
||||
$callBackLog->error($hdr . $msg);
|
||||
} else {
|
||||
$msg = SUCCESS_DB_UPSERT_COUNT . $recordCount;
|
||||
$eventSuccess = true;
|
||||
$retData = [
|
||||
STRING_REC_COUNT_INSERTED => $recordCount,
|
||||
STRING_GENERATED_DATE => $lastUpdated
|
||||
];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, $retData]);
|
||||
echo 'FQFN: ' . $newFileName . PHP_EOL; // todo: delete me
|
||||
$tmpObj->template->cleanUp($newFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_object($tmpObj)) $tmpObj->__destruct();
|
||||
unset($tmpObj);
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_REMOTE_FETCH :
|
||||
$eventTimer = true;
|
||||
$errors = [];
|
||||
/** @var gacMongoDB $tmpObj */
|
||||
if (is_null($tmpObj = grabWidget($request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
// todo -- this is WRONG - use the core call: remoteFetchRequest() instead!
|
||||
$tmpObj->_fetchRecords($request[BROKER_DATA]);
|
||||
if ($tmpObj->status) {
|
||||
$eventSuccess = true;
|
||||
$tmpObj->eventMessages[] = STRING_REC_COUNT_RET . $tmpObj->recordsReturned;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_FETCH;
|
||||
$queryMeta = [
|
||||
STRING_REC_COUNT_RET => $tmpObj->recordsReturned,
|
||||
STRING_REC_COUNT_TOT => $tmpObj->recordsInCollection
|
||||
];
|
||||
// recordsInQuery is a PDO thing so let's see if it exists in the class object
|
||||
if (isset($tmpObj->recordsInQuery) and $tmpObj->recordsInQuery) {
|
||||
$queryMeta[STRING_REC_COUNT_QUERY] = $tmpObj->recordsInQuery;
|
||||
}
|
||||
if (isset($request[BROKER_META_DATA][META_DONUT_FILTER]) and $request[BROKER_META_DATA][META_DONUT_FILTER] == 1) {
|
||||
$queryResults = $tmpObj->getData();
|
||||
} elseif ($tmpObj->useCache or (isset($request[BROKER_META_DATA][META_DO_CACHE]) and $request[BROKER_META_DATA][META_DO_CACHE])) {
|
||||
// todo - this is supposed to return the list of cache keys, or the single reference cache key - fix!
|
||||
$queryResults = $tmpObj->cacheMap;
|
||||
} else {
|
||||
$queryResults = $tmpObj->getData();
|
||||
}
|
||||
$retData = [STRING_QUERY_RESULTS => $queryResults, STRING_QUERY_DATA => $queryMeta];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $tmpObj->eventMessages, $retData]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_FETCH;
|
||||
$aryRetData = buildReturnPayload([false, $tmpObj->state, $tmpObj->eventMessages, null]);
|
||||
}
|
||||
if (is_object($tmpObj)) $tmpObj->__destruct();
|
||||
unset($tmpObj);
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, $msg, null]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $t->getMessage(), $errorStack]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData) and $postNormalResponse) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_M . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
|
||||
// prepare and send the return payload if we've not already sent it...
|
||||
if ($postNormalResponse)
|
||||
postResponse($aryRetData, $_request, $callBackLog, $res);
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
// todo: core-452: publish the event payload to the sysEvent broker to capture the failed event
|
||||
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT,$requestCounter, $myRequestsPerInstance));
|
||||
unset($msg);
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_WH, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_WH));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
420
brokers/mBroker.php
Normal file
420
brokers/mBroker.php
Normal file
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
/**
|
||||
* mBroker.php
|
||||
*
|
||||
* This is the migration broker and is a rare-use broker that should normally not be spun-up unless you're planning
|
||||
* on a data migration. Otherwise, most of the time, this broker should not be active or available since it runs
|
||||
* off the main application server and therefore would be "visible" to anyone with access to the Namaste service.
|
||||
*
|
||||
* This broker is used to pull data from a remote mongo or mysql database and import the entire table/collection into
|
||||
* the "local" mysql or mongo database.
|
||||
*
|
||||
* You can, as of this writing:
|
||||
*
|
||||
* migrate mysql --> mongo
|
||||
* migrate mongo --> mysql
|
||||
*
|
||||
* To do so, the XML file, migration section, must be populated with the data defining the source resource. (URI,
|
||||
* port, authentication, database name, table or collection name.) The remote service must be available and accessible
|
||||
* to the Namaste service.
|
||||
*
|
||||
* Secondly, the destination table must contain a "migration" section in the template file. The migration data in the
|
||||
* template maps the source data to the new data source.
|
||||
*
|
||||
* This is an RPC broker - however, the migration event exposes no data and no schema to the calling client. The
|
||||
* response payload is limited to simply a boolean status and a count of the number of records that were transferred
|
||||
* and the total amount of time take to complete the migration.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-19-18 mks INF-139: Original coding
|
||||
* 02-08-18 mks INF-139: Added migration events, PHP 7.2 exception handling
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 10-04-18 mks DB-43: Support for migration requests coming from the awesome web app
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
$file = basename(__FILE__);
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'MIGB: ';
|
||||
|
||||
// before we do anything, ensure we have a "migration" section in the configuration
|
||||
if (!array_key_exists(CONFIG_MIGRATION, gasConfig::$settings)
|
||||
or empty(gasConfig::$settings[CONFIG_MIGRATION])
|
||||
or !is_array(gasConfig::$settings[CONFIG_MIGRATION])) {
|
||||
// XML config for migration is not loaded or is empty or malformed - exit immediately
|
||||
consoleLog($res, CON_SYSTEM, ERROR_CONFIG_RESOURCE_404 . STRING_MIGRATION_CONFIG);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
// event management for children
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER];
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_M_BROKER];
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// todo - validate the broker environment as declared in the XML config
|
||||
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_APPSERVER;
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = CONFIG_BROKER_APPSERVER;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $startingMemory, $myRequestsPerInstance, $groot, $file;
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
try {
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
$queue = $queueTag . BROKER_QUEUE_M;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_BROKER);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
// todo -- add a broker name to this event so we know which broker is registering
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
$event = BROKER_QUEUE_M . '(';
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$errorStack = [];
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
try {
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event .= ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorStack)) {
|
||||
for ($index = 0, $last = count($errorStack); $index < $last; $index++) {
|
||||
$conMsg .= $errorStack[$index] . $eos;
|
||||
$callBackLog->error($errorStack[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorStack, null, null]);
|
||||
$event .= ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event .= $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_REQUEST_404);
|
||||
}
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_M;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_M), null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// BROKER_REQUEST_MIGRATION event starts the migration process
|
||||
case BROKER_REQUEST_MIGRATION :
|
||||
// check to see if this is a web-request (with replacement XML)
|
||||
if (isset($request[BROKER_META_DATA][BROKER_XML_DATA]) and is_array($request[BROKER_META_DATA][BROKER_XML_DATA])) {
|
||||
// store the old XML settings
|
||||
// $oldMigCfg = gasConfig::$settings[CONFIG_MIGRATION];
|
||||
// replace with the new XML configuration validated by the migration web app
|
||||
// gasConfig::$settings[CONFIG_MIGRATION] = $request[BROKER_META_DATA][BROKER_XML_DATA];
|
||||
// unset($request[BROKER_META_DATA][BROKER_XML_DATA]);
|
||||
// set a meta field to indicate that the origin was the migration web app
|
||||
// $request[BROKER_META_DATA][META_MIGRATION_WEB_APP] = true;
|
||||
consoleLog($res, CON_SYSTEM, INFO_MIGRATION_XML_OVERRIDE);
|
||||
}
|
||||
// process the request
|
||||
$objMigrate = new gacMigrations($request[BROKER_DATA], $request[BROKER_META_DATA]);
|
||||
// reset XML back to original settings
|
||||
if (isset($oldMigCfg)) gasConfig::$settings[CONFIG_MIGRATION] = $oldMigCfg;
|
||||
if (!$objMigrate->status) {
|
||||
// migration process did not complete or even failed to launch
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_MIGRATION;
|
||||
$aryRetData = buildReturnPayload([false, $objMigrate->state, $objMigrate->errorStack, null]);
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_MIGRATION;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $objMigrate->errorStack, $objMigrate->migrationReport]);
|
||||
$eventSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, $msg, null]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $t->getMessage(), $errorStack]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_M . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
|
||||
// prepare the return payload...
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
} catch (PhpAmqpLib\Exception\AMQPTimeoutException | PhpAmqpLib\Exception\AMQPRuntimeException | Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
// todo: core-452: publish the event payload to the sysEvent broker to capture the failed event
|
||||
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT,$requestCounter, $myRequestsPerInstance));
|
||||
unset($msg);
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_M, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_M));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
575
brokers/rBroker.php
Normal file
575
brokers/rBroker.php
Normal file
@@ -0,0 +1,575 @@
|
||||
<?php
|
||||
/**
|
||||
* readBroker (rBroker.php) -- persistent (daemon) PHP application program
|
||||
*
|
||||
* This is a forking-broker. Which means that, upon execution, the broker program will iteratively start-up a
|
||||
* specific number of child-processes (XML config) and then, as the parent process, will monitor each child.
|
||||
* On a child's death, the signal is trapped via a replacement, custom, signal handler, and a replacement child
|
||||
* is restarted.
|
||||
*
|
||||
* Children are only allowed to execute a finite number of broker events (XML config) before they self-terminate and
|
||||
* are re-incarnated by the parent. This is to mitigate the memory leaks inherent in PHP as PHP applications were
|
||||
* never intended to be used as TSR programs.
|
||||
*
|
||||
* NOTES:
|
||||
* ------
|
||||
* - only the parent PID is written to the PID directory. This feature is for a monitoring program that will restart
|
||||
* the parent broker, but will not monitor/restart the children; only the parent daemon may re-incarnate new children
|
||||
* - custom signal handler for trapping SIGCLD and updating the global child counter
|
||||
* - signals sent to a child (other than SIGKILL) are diverted to the shutDown event RMQ resources are freed
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-14-17 mks original coding
|
||||
* 08-24-17 mks CORE-500: broker events
|
||||
* 03-14-18 mks CORE-833: fetch event tests for recordsInQuery class member being set before including in the
|
||||
* return-data payload b/c recordsInQuery is only a PDO thing
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 01-03-19 mks DB-78: fixed bug in fetch event where pre-supplied event-GUID value was being over-written
|
||||
* 01-29-20 mks DB-145: router code for tercero requests added to default section in $callback method
|
||||
* 04-03-20 mks ECI-107: added sub-collection fetch, exception trapping on wait(), IDE directives cleaned-up
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPChannelClosedException;
|
||||
use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true; // all output to logfile
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
|
||||
$childrenPidList = null; // contains list of the pids of the children spawned by this watcher
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$res = 'RBRK: ';
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER];
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_R_BROKER];
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren;
|
||||
$runningBrokers = $numberChildren;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$file = basename(__FILE__);
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_APPSERVER;
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = CONFIG_BROKER_APPSERVER;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot, $file;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error!!!
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// remove the signal handlers in the child code
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
try {
|
||||
// set-up the child error logger
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// ---- broker code begins ---- //
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
//$exchange = BROKER_EXCHANGE_RO;
|
||||
$queue = $queueTag . BROKER_QUEUE_R;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_BROKER);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
|
||||
// set up the RPC queue for RO service
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
//$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
global $requestCounter, $groot, $res, $eos, $myRequestsPerInstance, $startingMemory, $service;
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$request = null;
|
||||
$errorList = [];
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the callBack log; logger object for the callback function
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, $msg, null, null]);
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_R . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
if (count($errorList) == 0) {
|
||||
$callBackLog->error(ERROR_DATA_META_REJECTED . STRING_UNKNOWN);
|
||||
$errorList[] = ERROR_DATA_META_REJECTED . STRING_UNKNOWN;
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
} else {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
}
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorList, null]);
|
||||
$event = BROKER_QUEUE_R . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_R . '(' . $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) consoleLog($res, CON_ERROR, ERROR_BROKER_REQUEST_404);
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN . BROKER_QUEUE_R;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN]);
|
||||
$eventSuccess = false;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_R;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, SUCCESS_PING . BROKER_QUEUE_R]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// request class schema map
|
||||
case BROKER_REQUEST_SCHEMA :
|
||||
$eventTimer = true;
|
||||
if (empty($request[BROKER_META_DATA]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_DATA_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, null, ERROR_DATA_404]);
|
||||
} else {
|
||||
$obj = null;
|
||||
$errorList = array();
|
||||
$processObject = false;
|
||||
// instantiate the new template class and return a schema report...
|
||||
try {
|
||||
// cant instantiate remove-service objects in production, so we'll inject an skip
|
||||
// directive for the env-check...
|
||||
$obj = new gacFactory($request[BROKER_META_DATA], FACTORY_EVENT_SCHEMA_REQUEST, '', $errorList);
|
||||
$processObject = true;
|
||||
} catch (TypeError $e) {
|
||||
$callBackLog->mirror = true;
|
||||
$callBackLog->warn($e->getMessage());
|
||||
$callBackLog->mirror = false;
|
||||
$conMsg = ERROR_EXCEPTION;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, [$msg], null]);
|
||||
}
|
||||
if ($processObject) {
|
||||
if (!$obj->status) {
|
||||
$msg = ERROR_CLASS_SCHEMA_404 . COLON . $request[BROKER_META_DATA][META_TEMPLATE];
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($msg);
|
||||
$errorList[] = $msg;
|
||||
if (!empty($obj->eventMessages)) $errorList = array_merge($errorList, $obj->eventMessages);
|
||||
$aryRetData = buildReturnPayload([false, STATE_TEMPLATE_ERROR, $errorList, null]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, $obj->schema]);
|
||||
}
|
||||
}
|
||||
if (is_object($obj)) $obj->__destruct();
|
||||
unset($obj);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_FETCH :
|
||||
$eventTimer = true;
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_CREATE]);
|
||||
} else {
|
||||
// invoke the broker-helper to execute the fetch request
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->fetch($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_SUBC_FETCH :
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_SUBC_FETCH]);
|
||||
} elseif (!isset($request[BROKER_DATA][STRING_SUBC_COL]) or empty($request[BROKER_DATA][STRING_SUBC_COL])) {
|
||||
$conMsg = ERROR_DATA_KEY_404 . STRING_SUBC_COL;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $conMsg, BROKER_REQUEST_SUBC_FETCH]);
|
||||
} elseif (!isset($request[BROKER_DATA][STRING_SUBC_DATA]) or empty($request[BROKER_DATA][STRING_SUBC_DATA])) {
|
||||
$conMsg = ERROR_DATA_KEY_404 . STRING_SUBC_DATA;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $conMsg, BROKER_REQUEST_SUBC_FETCH]);
|
||||
} else {
|
||||
$errors = [];
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
// todo -- for now, sub-collection fetches are only allowed on appServer
|
||||
// check that this is a mongo object, exit if it is not
|
||||
if ($objClass->schema != TEMPLATE_DB_MONGO) {
|
||||
$conMsg = ERROR_SCHEMA_MISMATCH . $request[BROKER_META_DATA][META_TEMPLATE];
|
||||
$errors[] = $conMsg;
|
||||
$errors[] = INFO_SCHEMA . $objClass->schema;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, $errors, null]);
|
||||
} else {
|
||||
$objClass->fetchSubCollectionRecord($request[BROKER_DATA]);
|
||||
if (!$objClass->status) {
|
||||
$conMsg = ERROR_SUBC_FETCH;
|
||||
$aryRetData = buildReturnPayload([ false, $objClass->state, $objClass->eventMessages, null]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_SUBC_FETCH;
|
||||
$queryMeta = [
|
||||
STRING_REC_COUNT_RET => $objClass->recordsReturned,
|
||||
STRING_REC_COUNT_QUERY => $objClass->recordsInQuery,
|
||||
STRING_REC_COUNT_TOT => $objClass->recordsInCollection
|
||||
];
|
||||
if ($objClass->state == STATE_NOT_FOUND and $objClass->count == 0) {
|
||||
$retData = [STRING_QUERY_RESULTS => null, STRING_QUERY_DATA => $queryMeta];
|
||||
} else {
|
||||
// cacheMapping call
|
||||
if (!gasCache::mapOutboundPayload($objClass, $errors)) {
|
||||
$queryResults = $objClass->getData();
|
||||
} else {
|
||||
// cache mapping succeeded - return the cache key
|
||||
$queryResults = $objClass->getCK();
|
||||
}
|
||||
$retData = [STRING_QUERY_RESULTS => $queryResults, STRING_QUERY_DATA => $queryMeta];
|
||||
}
|
||||
$aryRetData = buildReturnPayload([true, $objClass->state, $objClass->eventMessages, $retData]);
|
||||
}
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_QUERY_COUNT :
|
||||
$eventTimer = true;
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_CREATE]);
|
||||
} else {
|
||||
$errors = [];
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
if (!$objClass->_getQC($request[BROKER_DATA])) {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_QUERY_COUNT;
|
||||
$aryRetData = buildReturnPayload([ false, $objClass->state, $objClass->eventMessages, null]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_QUERY_COUNT;
|
||||
$aryRetData = buildReturnPayload([ true, STATE_SUCCESS, $objClass->eventMessages, [$objClass->recordsInQuery, $objClass->recordsInCollection ] ] );
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_TERCERO :
|
||||
$eventTimer = true;
|
||||
// just as a reminder, we don't check for the existence of META_TEMPLATE in the validateMetaData()
|
||||
// function because not all events require it - hence the seemingly repetitive check in the event code.
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} elseif (!isset($request[OLD_REQUEST]) or empty($request[OLD_REQUEST])) {
|
||||
$conMsg = ERROR_REQUEST_404 . COLON . OLD_REQUEST;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $conMsg, null]);
|
||||
} else {
|
||||
// this is a request for tercero - replace the event, instantiate a tercero client,
|
||||
// and cross-service publish the request and return the response back to the caller
|
||||
$bc = new gacBrokerClient(BROKER_QUEUE_U, sprintf(INFO_LOC, basename(__FILE__), __LINE__));
|
||||
if (!$bc->status) {
|
||||
$conMsg = ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_U;
|
||||
$aryRetData = buildReturnPayload([ false, STATE_FRAMEWORK_WARNING, $conMsg, null]);
|
||||
} else {
|
||||
$request[BROKER_REQUEST] = $request[OLD_REQUEST];
|
||||
$aryRetData = json_decode(gzuncompress($bc->call(gzcompress(json_encode($request)))),true);
|
||||
if ($aryRetData[PAYLOAD_STATUS]) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[OLD_REQUEST] . ' for ' . BROKER_TERCERO;
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . $request[OLD_REQUEST] . ' for ' . BROKER_TERCERO;
|
||||
}
|
||||
}
|
||||
if (is_object($bc)) $bc->__destruct();
|
||||
unset($bc);
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
// check for user template in meta payload and, if exists, publish the request to the user
|
||||
// and pass the return payload back to the requesting client
|
||||
if (isset($request[BROKER_META_DATA][META_TEMPLATE]) and $request[BROKER_META_DATA][META_TEMPLATE] == TEMPLATE_CLASS_USERS) {
|
||||
$ubc = new gacBrokerClient(BROKER_QUEUE_U, basename(__FILE__) . AT . __LINE__);
|
||||
if (!$ubc->status) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_U;
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg]);
|
||||
} else {
|
||||
$response = $ubc->call($request);
|
||||
$response = json_decode(gzuncompress($response), true);
|
||||
$aryRetData = buildReturnPayload([$response[PAYLOAD_STATUS], $response[PAYLOAD_STATE], $response[PAYLOAD_DIAGNOSTICS], $response[PAYLOAD_RESULTS]]);
|
||||
if ($response[PAYLOAD_STATUS]) {
|
||||
$conMsg = SUCCESS_EVENT;
|
||||
$eventSuccess = true;
|
||||
} else $conMsg = FAIL_EVENT;
|
||||
$conMsg .= $request[BROKER_REQUEST];
|
||||
if (is_object($ubc)) $ubc->__destruct();
|
||||
unset($ubc);
|
||||
}
|
||||
} else {
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, null, $msg]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make doubly-damn sure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$msg = ERROR_NO_RET_DATA;
|
||||
$conMsg = BROKER_QUEUE_R . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
|
||||
// prepare the return payload...
|
||||
// $eventSuccess = false;
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
} catch (AMQPTimeoutException | TypeError | AMQPRuntimeException | Throwable $e) {
|
||||
$m = $e->getMessage();
|
||||
$callBackLog->fatal($m);
|
||||
consoleLog($res, CON_ERROR, $m);
|
||||
}
|
||||
|
||||
// if the event processing failed, we want to publish the failed event to the admin queue
|
||||
// if (!$eventSuccess) {
|
||||
// todo - CORE-452 - publish the event(payload) to the admin queue to capture the failed event
|
||||
// }
|
||||
|
||||
unset($msg);
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT,$requestCounter, $myRequestsPerInstance));
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->disconnect(); // changed from close() which DNE
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_R, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (AMQPChannelClosedException | AMQPInvalidArgumentException | AMQPRuntimeException| Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
// ---- broker code ends ---- //
|
||||
break;
|
||||
case 1 : // parent
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_R));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run...it looks for any of the children in it's process group to die...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
381
brokers/sBroker.php
Normal file
381
brokers/sBroker.php
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
/**
|
||||
* sBroker.php -- the tercero session (one-way) broker
|
||||
*
|
||||
* The session broker is a "system" broker designed to basically do one thing - handle requests to expire existing
|
||||
* sessions on tercero from the admin service.
|
||||
*
|
||||
* This broker was created so as to not overly-burden the user-broker with administrative requests. The broker is
|
||||
* a "fire-n-forget" broker meaning that no response is published (returned) to the calling client.
|
||||
*
|
||||
* If there is an error in processing, then we'll communicate that error back to admin by publishing a system event.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-02-20 mks DB-168: original coding
|
||||
*
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPChannelClosedException;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'SESS: ';
|
||||
|
||||
// event management for children
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_TERCERO];
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_SESSION_BROKER];
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2?? (Yes, but only if prod)
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
$parentLog = new gacErrorLogger();
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_TERCERO;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(0, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
try {
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
|
||||
$queue = $queueTag . BROKER_QUEUE_S;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_TERCERO);
|
||||
if (is_null($brokerConnection)) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
$childLog->fatal($hdr . ERROR_RESOURCE_404 . RESOURCE_TERCERO . COLON . BROKER_QUEUE_S);
|
||||
consoleLog($res, CON_ERROR,$hdr . ERROR_RESOURCE_404 . RESOURCE_TERCERO . COLON . BROKER_QUEUE_S);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// $brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
$brokerChannel->queue_declare($queue);
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the broker child start-up as a system-event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
$file = basename(__FILE__);
|
||||
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
consoleLog($res, CON_DEBUG, 'Child GUID: ' . $childGUID);
|
||||
consoleLog($res,CON_DEBUG, 'root GUID: ' . $groot);
|
||||
}
|
||||
|
||||
$requestCounter++;
|
||||
$returnData = null;
|
||||
$eventTimer = false;
|
||||
$request = null;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$thisPid = getmypid();
|
||||
$eventGUID = guid();
|
||||
$ogGUID = '';
|
||||
/** @var gacMongoDB $obj */
|
||||
$obj = null;
|
||||
|
||||
// set-up the call-back logger
|
||||
$callBackLog = new gacErrorLogger($eventGUID, false);
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$event = BROKER_QUEUE_S . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$event = BROKER_QUEUE_S . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_S . '(' . $request[BROKER_REQUEST] . ')';
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_S;
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_EXPIRE_SESSION :
|
||||
$errors = [];
|
||||
/** var gacMongoDB $obj */
|
||||
if (!is_null($obj = grabWidget($request[BROKER_META_DATA], '', $errors))) {
|
||||
// we have widget - update the session record
|
||||
/** @var gatSessions $template */
|
||||
$template = $obj->template;
|
||||
$bc = new gacWorkQueueClient($file . AT . __LINE__, BROKER_QUEUE_AI);
|
||||
if (!$bc->status) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_AI, $foo, true);
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
} elseif (!is_null($payload = $template->buildExpireSessionPayload($request[BROKER_DATA], $errors))) {
|
||||
$obj->_updateRecord($payload);
|
||||
if ($obj->status) {
|
||||
// publish a request back to admin to expire the system-event record indicating success in closing the session
|
||||
// (because both of these queues are type f-n-f...)
|
||||
$bc->call($template->buildCloseSysEventPayload($request[BROKER_DATA][STRING_GUID_KEY]));
|
||||
// successful session update - console log message and done (no return to client)
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
$eventSuccess = true;
|
||||
} else {
|
||||
// create failed-session record for failure to update session record
|
||||
if (count($errors))
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
$data = [
|
||||
MONGO_FAILED_EVENT_GUID => $request[BROKER_DATA][STRING_GUID_KEY],
|
||||
MONGO_FAILED_EVENT_NAME => $request[BROKER_REQUEST],
|
||||
MONGO_FAILED_EVENT_DESC => basename(__FILE__) . AT . __LINE__,
|
||||
MONGO_FAILED_EVENT_SEV => ERROR_WARN
|
||||
];
|
||||
$meta = [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_FAILED_SESSIONS,
|
||||
META_CLIENT => CLIENT_SYSTEM,
|
||||
META_DO_CACHE => 0,
|
||||
META_SESSION_ID => $request[BROKER_DATA][STRING_GUID_KEY],
|
||||
];
|
||||
$request = [
|
||||
BROKER_REQUEST => BROKER_REQUEST_CREATE,
|
||||
BROKER_DATA => [$data],
|
||||
BROKER_META_DATA => $meta
|
||||
];
|
||||
$bc->call(gzcompress(json_encode($request)));
|
||||
if (is_object($bc)) $bc->__destruct();
|
||||
unset($bd);
|
||||
}
|
||||
} else {
|
||||
// we somehow failed to build the data payload based on the request data
|
||||
if (count($errors))
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
}
|
||||
} else {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$conMsg = ERROR_TEMPLATE_INSTANTIATE . $request[BROKER_META_DATA][META_TEMPLATE];
|
||||
$obj->eventMessages[] = $conMsg;
|
||||
$callBackLog->warn($hdr . $conMsg);
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$conMsg = ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST];
|
||||
$callBackLog->warn(ERROR_BROKER_EVENT_UNKNOWN . $request[BROKER_REQUEST]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = ERROR_FINE_PICKLE;
|
||||
}
|
||||
if (!empty($conMsg)) {
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
}
|
||||
// $_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
|
||||
// log a system-event for the event -- unlike the other system events, we're not going to submit
|
||||
// this one via a broker - which is standard but, instead, we're going to write the record out
|
||||
// directly since doing otherwise would cause an infinite loop in processing.
|
||||
if ($eventTime and $eventTimer) {
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($ogGUID)) $data[SYSTEM_EVENT_OGUID] = $ogGUID;
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
gasCache::sysDel(($groot . UDASH . $thisPid));
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_S, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_consume($queue, '', false, true, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (AMQPChannelClosedException | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_S));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
485
brokers/uBroker.php
Normal file
485
brokers/uBroker.php
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* uBroker.php -- user broker for tercero service
|
||||
*
|
||||
* The user broker lives on tercero and handles all user API requests initially published to appServer which is then
|
||||
* forwarded here to this broker.
|
||||
*
|
||||
* API calls are fully documented.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-28-20 mks DB-144: original coding
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
$file = basename(__FILE__);
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'USRB: '; // USRB: USeR Broker
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
// event management for children
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_TERCERO];
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_USER_BROKER];
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// todo - validate the broker environment as declared in the XML config
|
||||
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_TERCERO;
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_TERCERO;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $startingMemory, $myRequestsPerInstance, $groot, $file;
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
try {
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
$queue = $queueTag . BROKER_QUEUE_U;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_TERCERO);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
// todo -- add a broker name to this event so we know which broker is registering
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection, $file;
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service;
|
||||
$event = BROKER_QUEUE_U . '(';
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$errorStack = [];
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
try {
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event .= ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorStack)) {
|
||||
for ($index = 0, $last = count($errorStack); $index < $last; $index++) {
|
||||
$conMsg .= $errorStack[$index] . $eos;
|
||||
$callBackLog->error($errorStack[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorStack, null, null]);
|
||||
$event .= ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event .= $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_REQUEST_404);
|
||||
}
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_U;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_U), null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// your events for this broker start here
|
||||
|
||||
case BROKER_REQUEST_CREATE :
|
||||
$eventTimer = true;
|
||||
$msg = '';
|
||||
// validate that we have a data-template in meta
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_CREATE]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->create($request, $aryRetData, $msg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_FETCH :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_CREATE]);
|
||||
} else {
|
||||
// invoke the broker-helper to execute the fetch request
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->fetch($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_UPDATE :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->update($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_DELETE :
|
||||
$eventTimer = true;
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->delete($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_VALIDATE_EMAIL :
|
||||
$eventTimer = true;
|
||||
$obj = null;
|
||||
try {
|
||||
$obj = new gacUsers($request[BROKER_META_DATA]);
|
||||
if (!$obj->status) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = ERROR_TEMPLATE_INSTANTIATE . TEMPLATE_CLASS_USERS;
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg]);
|
||||
$callBackLog->warn($hdr . $msg);
|
||||
} else {
|
||||
$obj->validateUserEmail($request[BROKER_DATA][STRING_QUERY_DATA][USER_PII_EMAIL . $obj->ext]);
|
||||
if ($obj->status) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_VALIDATE_EMAIL;
|
||||
$aryRetData = buildReturnPayload([true, $obj->state, null, null]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_VALIDATE_EMAIL;
|
||||
$aryRetData = buildReturnPayload([false, $obj->state, null, null]);
|
||||
}
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
if (is_object($obj)) {
|
||||
$obj->eventMessages[] = ERROR_EXCEPTION;
|
||||
$aryRetData = buildReturnPayload([ false, STATE_FRAMEWORK_FAIL, $obj->eventMessages, null]);
|
||||
} else {
|
||||
$aryRetData = buildReturnPayload([ false, STATE_FRAMEWORK_FAIL, ERROR_EXCEPTION, null]);
|
||||
}
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
if (is_object($obj)) $obj->__destruct();
|
||||
unset($obj);
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_REGISTER_ACCOUNT :
|
||||
$eventTimer = true;
|
||||
try {
|
||||
$obj = new gacUsers($request[BROKER_META_DATA]);
|
||||
if (!$obj->status) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = ERROR_TEMPLATE_INSTANTIATE . $request[BROKER_META_DATA][META_TEMPLATE];
|
||||
$conMsg = $msg;
|
||||
$callBackLog->error($hdr . $msg);
|
||||
$aryRetData = buildReturnPayload([false, $obj->state, $obj->eventMessages, null]);
|
||||
} else {
|
||||
$obj->registerNewUser($request);
|
||||
if ($obj->status) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, [STRING_USER => $obj->userGUID, STRING_SESSION => $obj->sessionGUID]]);
|
||||
} else {
|
||||
$conMsg = ERROR_USER_REG_FAIL;
|
||||
$aryRetData = buildReturnPayload([false, $obj->state, $obj->eventMessages, null]);
|
||||
}
|
||||
}
|
||||
if (is_object($obj)) $obj->__destruct();
|
||||
unset($obj);
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
break;
|
||||
|
||||
// events for this broker end here
|
||||
|
||||
default :
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, $msg, null]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
consoleLog($res, CON_SYSTEM, $t->getMessage());
|
||||
$callBackLog->fatal($t->getMessage());
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $t->getMessage(), $errorStack]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_M . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn( ERROR_NO_CON_MSG . STRING_FOR . $request[BROKER_REQUEST]);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
} elseif (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_FAIL;
|
||||
}
|
||||
|
||||
// prepare the return payload...
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
} catch (PhpAmqpLib\Exception\AMQPTimeoutException | PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
// todo: core-452: publish the event payload to the sysEvent broker to capture the failed event
|
||||
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT, $requestCounter, $myRequestsPerInstance));
|
||||
unset($msg);
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_U, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_U));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
598
brokers/wBroker.php
Normal file
598
brokers/wBroker.php
Normal file
@@ -0,0 +1,598 @@
|
||||
<?php
|
||||
/**
|
||||
* wBroker.php -- write broker
|
||||
*
|
||||
* the write broker handles all destructive CRUD events for all of the framework classes.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 08-22-17 mks CORE-500: publishing broker events as system events to ADMIN service
|
||||
* 09-11-17 mks CORE-501: new record requests: data count cannot exceed declared payload limits
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 07-09-18 mks CORE-1017: pedigree fetch event added
|
||||
* 07-10-18 mks CORE-773: replaced echo statements with consoleLog()
|
||||
* 01-28-19 mks DB-107: fixed bug: if meta payload has event guid submitted, no longer overwriting it
|
||||
* 01-29-20 mks DB-145: router code for tercero requests added to default section in $callback method
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
* 09-17-20 mks DB-168: updated service registration, updated exception handling to current standard
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
|
||||
$childrenPidList = null; // contains list of the pids of the children spawned by this watcher
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$res = 'WBRK: ';
|
||||
|
||||
// event management
|
||||
$appServerConfig = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER];
|
||||
$numberChildren = $appServerConfig[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_W_BROKER];
|
||||
$requestsPerInstance = (empty($appServerConfig[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $appServerConfig[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren;
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS,sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = (!empty($argv) and !empty($argv[1])) ? $argv[1] : ENV_APPSERVER;
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = CONFIG_BROKER_APPSERVER;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//declare( ticks = 1);
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $myRequestsPerInstance, $startingMemory, $groot;
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$thisPid = pcntl_fork();
|
||||
switch ($thisPid) {
|
||||
case -1 : // error!!!
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
try {
|
||||
// replace the signal handlers in the child code
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
// init the child log
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
// ---- broker code begins ---- //
|
||||
$queueTag = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG];
|
||||
//$exchange = BROKER_EXCHANGE_WO;
|
||||
$queue = $queueTag . BROKER_QUEUE_W;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_BROKER);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
consoleLog($res, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
||||
exit(0);
|
||||
}
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
$brokerChannel = $brokerConnection->channel(); // params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable | TypeError $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service, $file;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$res = 'WBRK: ';
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$errorList = array();
|
||||
$eventGUID = guid();
|
||||
// $request[BROKER_META_DATA][META_EVENT_GUID] = $eventGUID; // inject the event guid
|
||||
$thisPid = getmypid();
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($res . $msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event = BROKER_QUEUE_W . '(' . ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorList)) {
|
||||
for ($index = 0, $last = count($errorList); $index < $last; $index++) {
|
||||
$conMsg .= $errorList[$index] . $eos;
|
||||
$callBackLog->error($errorList[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorList, null, null]);
|
||||
$event = BROKER_QUEUE_W . '(' . ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event = BROKER_QUEUE_W . '(' . $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_BROKER_REQUEST_404);
|
||||
}
|
||||
|
||||
// DB-57: stash the broker guids in the meta for audit and journaling
|
||||
$request[META_BROKER_CHILD_GUID] = $childGUID;
|
||||
$request[META_BROKER_GROOT] = $groot;
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
// shutdown gracefully
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_W;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, SUCCESS_PING . BROKER_QUEUE_W]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PEDIGREE :
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_PEDIGREE;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, gasConfig::getPedigree()]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// create new record event
|
||||
case BROKER_REQUEST_CREATE :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
// validate that we have a data-template in meta
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, BROKER_REQUEST_CREATE]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->create($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_UPDATE :
|
||||
$eventTimer = true;
|
||||
$conMsg = '';
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->update($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_DELETE :
|
||||
$eventTimer = true;
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
$bh = new gacBrokerHelper();
|
||||
$eventSuccess = $bh->delete($request, $aryRetData, $conMsg);
|
||||
unset($bh);
|
||||
}
|
||||
break;
|
||||
|
||||
// sub-collection events
|
||||
case BROKER_REQUEST_SUBC_CREATE :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
// CORE-501: validate the number of incoming records
|
||||
$qrl = intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT]);
|
||||
if (count($request[BROKER_DATA][STRING_DATA]) > $qrl) {
|
||||
$msg = ERROR_RECORD_LIMIT_EXCEEDED . $qrl;
|
||||
$callBackLog->data($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $msg, null]);
|
||||
} else {
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$objClass->pushSubCollectionEvent($request[BROKER_DATA]);
|
||||
if ($objClass->status) {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_SUBC_CREATE;
|
||||
$eventSuccess = true;
|
||||
$queryResults = (!gasCache::mapOutboundPayload($objClass, $errors)) ? $objClass->getData() : $objClass->getCK();
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, $queryResults]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_SUBC_CREATE;
|
||||
$aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_SUBC_DELETE :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$objClass->popSubCollection($request[BROKER_DATA]);
|
||||
if ($objClass->status) {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_SUBC_DELETE;
|
||||
$eventSuccess = true;
|
||||
$queryResults = (!gasCache::mapOutboundPayload($objClass, $errors)) ? $objClass->getData() : $objClass->getCK();
|
||||
$aryRetData = buildReturnPayload([true, $objClass->state, $objClass->eventMessages, $queryResults]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_SUBC_DELETE;
|
||||
$aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_CALL_SP :
|
||||
$eventTimer = true;
|
||||
$errors = array();
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
/** @var gacPDO $objClass */
|
||||
if (is_null($objClass = grabWidget($request[BROKER_META_DATA], '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
if ($objClass->schema != TEMPLATE_DB_PDO) {
|
||||
$msg = sprintf(ERROR_PDO_INVALID_EVENT, $request[BROKER_REQUEST], $objClass->class);
|
||||
$conMsg = $msg;
|
||||
$errors[] = $msg;
|
||||
$aryRetData = buildReturnPayload([false, FAIL_EVENT, $errors, null]);
|
||||
$callBackLog->error($msg);
|
||||
} else {
|
||||
$objClass->execSP($request[BROKER_DATA]);
|
||||
if ($objClass->status) {
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
$eventSuccess = true;
|
||||
$aryRetData = buildReturnPayload([true, $objClass->state, $objClass->eventMessages, $objClass->queryResults]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
$aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_WAREHOUSE :
|
||||
$eventTimer = true;
|
||||
$objClass = new gacBrokerClient(BROKER_QUEUE_WH, basename(__FILE__) . COLON_NS . __LINE__);
|
||||
if (!$objClass->status or is_null($objClass)) {
|
||||
$error = ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_WH . EVENT_TYPE . COLON . BROKER_REQUEST_WAREHOUSE;
|
||||
$conMsg = $error;
|
||||
$aryRetData = buildReturnPayload([false, STATE_RESOURCE_ERROR, $error, null]);
|
||||
} else {
|
||||
$response = json_decode(gzuncompress($objClass->call($_request->body)), true);
|
||||
if (!$response[PAYLOAD_STATUS]) {
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST];
|
||||
$aryRetData = buildReturnPayload([false, $response[PAYLOAD_STATE], $response[PAYLOAD_DIAGNOSTICS], $response[PAYLOAD_RESULTS]]);
|
||||
} else {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $response[PAYLOAD_DIAGNOSTICS], $response[PAYLOAD_RESULTS]]);
|
||||
}
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_TERCERO :
|
||||
$eventTimer = true;
|
||||
try {
|
||||
if (!isset($request[OLD_REQUEST])) {
|
||||
$conMsg = sprintf(ERROR_REQ_FIELD_404, OLD_REQUEST);
|
||||
$aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $conMsg, null]);
|
||||
break;
|
||||
}
|
||||
// just as a reminder, we don't check for the existence of META_TEMPLATE in the validateMetaData()
|
||||
// function because not all events require it - hence the seemingly repetitive check in the event code.
|
||||
if (!isset($request[BROKER_META_DATA][META_TEMPLATE]) or empty($request[BROKER_META_DATA][META_TEMPLATE])) {
|
||||
$conMsg = ERROR_TEMPLATE_FILE_404;
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, ERROR_TEMPLATE_FILE_404, null]);
|
||||
} else {
|
||||
// this is a request for tercero - replace the event, instantiate a tercero client,
|
||||
// and cross-service publish the request and return the response back to the caller
|
||||
$request[BROKER_REQUEST] = $request[OLD_REQUEST];
|
||||
unset($request[OLD_REQUEST]);
|
||||
$bc = new gacBrokerClient(BROKER_QUEUE_U, sprintf(INFO_LOC, basename(__FILE__), __LINE__));
|
||||
if (!$bc->status) {
|
||||
$conMsg = ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_U;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_WARNING, $conMsg, null]);
|
||||
} else {
|
||||
$aryRetData = json_decode(gzuncompress($bc->call(gzcompress(json_encode($request)))), true);
|
||||
if ($aryRetData[PAYLOAD_STATUS]) {
|
||||
$eventSuccess = true;
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST] . ' for ' . BROKER_TERCERO;
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST] . ' for ' . BROKER_TERCERO;
|
||||
}
|
||||
}
|
||||
if (is_object($bc)) $bc->__destruct();
|
||||
unset($bc);
|
||||
}
|
||||
} catch (Throwable | TypeError | AMQPRuntimeException $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
$aryRetData = buildReturnPayload([false. STATE_FRAMEWORK_WARNING, ERROR_EXCEPTION, null]);
|
||||
$conMsg = ERROR_EXCEPTION;
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_NULL_FIELD :
|
||||
default :
|
||||
// check for user template in meta payload and, if exists, publish the request to the user
|
||||
// and pass the return payload back to the requesting client
|
||||
if (isset($request[BROKER_META_DATA][META_TEMPLATE]) and $request[BROKER_META_DATA][META_TEMPLATE] == TEMPLATE_CLASS_USERS) {
|
||||
$ubc = new gacBrokerClient(BROKER_QUEUE_U, basename(__FILE__) . AT . __LINE__);
|
||||
if (!$ubc->status) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_U;
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg]);
|
||||
} else {
|
||||
$response = $ubc->call($request);
|
||||
$response = json_decode(gzuncompress($response), true);
|
||||
$aryRetData = buildReturnPayload([$response[PAYLOAD_STATUS], $response[PAYLOAD_STATE], $response[PAYLOAD_DIAGNOSTICS], $response[PAYLOAD_RESULTS]]);
|
||||
if ($response[PAYLOAD_STATUS]) {
|
||||
$conMsg = SUCCESS_EVENT;
|
||||
$eventSuccess = true;
|
||||
} else $conMsg = FAIL_EVENT;
|
||||
$conMsg .= $request[BROKER_REQUEST];
|
||||
if (is_object($ubc)) $ubc->__destruct();
|
||||
unset($ubc);
|
||||
}
|
||||
} else {
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, null, $msg]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
unset($aryRetData[PAYLOAD_CM]);
|
||||
if (is_null($aryRetData[PAYLOAD_DIAGNOSTICS])) unset($aryRetData[PAYLOAD_DIAGNOSTICS]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData)) {
|
||||
$conMsg = BROKER_QUEUE_W . ' - ' . ERROR_NO_RET_DATA;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$conMsg = SUCCESS_EVENT . $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
} elseif (!$eventSuccess and empty($conMsg)) {
|
||||
$conMsg = FAIL_EVENT . $request[BROKER_REQUEST] . ' - ' . STATE_FAIL;
|
||||
}
|
||||
|
||||
// prepare the return payload...
|
||||
try {
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$msg = new AMQPMessage(gzcompress(json_encode($aryRetData)), array(BROKER_CORRELATION_ID => $_request->get(BROKER_CORRELATION_ID)));
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_publish($msg, '', $_request->get(BROKER_REPLY_TO));
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_ack($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
|
||||
// if the event processing failed, we want to publish the failed event to the admin queue
|
||||
// if (!$eventSuccess) {
|
||||
// todo - CORE-452 - publish the event(payload) to the admin queue to capture the failed event
|
||||
// }
|
||||
unset($msg);
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT,$requestCounter, $myRequestsPerInstance));
|
||||
|
||||
// publish metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// post a broker system-event if we're recycling the broker
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
unset($msg);
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_W, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
// ---- broker code ends ---- //
|
||||
break;
|
||||
case 1 : // parent
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_W));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run...it looks for any of the children in it's process group to die...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
449
brokers/whBroker.php
Normal file
449
brokers/whBroker.php
Normal file
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
/**
|
||||
* whBroker.php
|
||||
*
|
||||
* This is the Namaste Warehouse broker which, by design, should be running on segundo, separately from both the
|
||||
* Appserver (namaste) and the admin services.
|
||||
*
|
||||
* Warehousing accepts requests from Namaste because we want writes to happen "locally" to this service.
|
||||
*
|
||||
* Warehousing is intended to support the following data transitions:
|
||||
*
|
||||
* COOL --> data is moved from HOT storage to COOL storage meaning that the original format of the data is preserved.
|
||||
* COLD --> data is moved from HOT or COOL storage to COLD storage -- which is TBD and is expected to be a CSV type
|
||||
* format using on of the AWS Storage-as-a-Service options.
|
||||
* WARM --> data is moved COLD to COOL storage. (so that it can be queried)
|
||||
* HOT --> data is moved COOL or COLD to HOT storage. (data de-archiving/recovery)
|
||||
*
|
||||
* For design notes, please refer to Jira case INF-188.
|
||||
*
|
||||
* This is a non-blocking RPC broker. Once a request is received from Namaste, we validate the request. If the
|
||||
* request passed validation and verification, then we'll immediately return a tracking GUID back to Namaste while
|
||||
* starting the migration process. The client has the responsibility to monitor the wareHousing record (created in
|
||||
* the ADMIN service database) progress and completion status. The GUID returned back to Namaste is the data
|
||||
* wareHousing record GUID.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-10-18 mks INF-201: Original coding (begins)
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 06-07-18 mks CORE-1013: remote-fetch event added
|
||||
* 07-09-18 mks CORE-1017: pedigree fetch event added
|
||||
* 07-28-20 mks DB-156: broker self-registration installed
|
||||
*
|
||||
*/
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Message\AMQPMessage;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
|
||||
pcntl_async_signals(true); // enable asynchronous signal handling (PHP 7.1)
|
||||
$myPid = getmypid();
|
||||
$_REDIRECT = true;
|
||||
$topDir = dirname(__DIR__);
|
||||
$thisWatcher = basename(__FILE__);
|
||||
$thisWatcher = rtrim($thisWatcher, ".php");
|
||||
|
||||
// load the framework
|
||||
@require_once($topDir . '/config/sneakerstrap.inc'); // can't be constants b/c this loads the constants
|
||||
$res = 'DATW: '; // dat warehouse
|
||||
|
||||
$childrenPidList = null;
|
||||
$pidDir = $topDir . DIR_PIDS;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
// event management for children
|
||||
$whServiceSettings = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_WH];
|
||||
$numberChildren = $whServiceSettings[CONFIG_BROKER_INSTANCES][CONFIG_BROKER_WH_BROKER];
|
||||
$requestsPerInstance = (empty($whServiceSettings[CONFIG_BROKER_REQUEST_LIMIT])) ? NUMBER_C : $whServiceSettings[CONFIG_BROKER_REQUEST_LIMIT];
|
||||
$numberChildren = ($numberChildren < 1) ? 1 : $numberChildren; // todo -- should this be = 2??
|
||||
$runningBrokers = $numberChildren;
|
||||
$requestCounter = 0;
|
||||
$myRequestsPerInstance = 0;
|
||||
$startingMemory = 0;
|
||||
// create the root guid
|
||||
$groot = rtrim($res, COLON) . UDASH . guid(); // root guid
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_STARTUP, substr(basename(__FILE__), 0, -4), $groot));
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_NUM_CHILD, substr(basename(__FILE__), 0, -4), $numberChildren));
|
||||
|
||||
/** @var gacErrorLogger $parentLog */
|
||||
$parentLog = new gacErrorLogger();
|
||||
|
||||
// todo - validate the broker environment as declared in the XML config
|
||||
// get the location of the broker is supposed to be run
|
||||
$brokerLocation = ENV_SEGUNDO;
|
||||
if (!empty($argv) and !empty($argv[1])) {
|
||||
$brokerLocation = $argv[1];
|
||||
}
|
||||
$errors = null;
|
||||
$file = rtrim(basename(__FILE__), DOT . FILE_TYPE_PHP);
|
||||
$service = ENV_SEGUNDO;
|
||||
|
||||
if (!validateService($service, $errors)) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_REG, $file, $service);
|
||||
$parentLog->fatal($hdr . $msg);
|
||||
$parentLog->__destruct();
|
||||
unset($parentLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the replacement signal handler that will be called on a child's death //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function sigHandler($_sig) {
|
||||
global $numberChildren;
|
||||
switch ($_sig) {
|
||||
case SIGCHLD :
|
||||
$numberChildren--;
|
||||
while (($pid = pcntl_wait($_sig, WNOHANG)) > 0) {
|
||||
@pcntl_wexitstatus($_sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pcntl_signal(SIGCLD, 'sigHandler');
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set-up the forking function so that it can be called initially or on a SIGCLD event //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
function forkMe()
|
||||
{
|
||||
global $thisWatcher, $eos, $res, $parentLog, $requestsPerInstance, $startingMemory, $myRequestsPerInstance, $groot, $file;
|
||||
$startingMemory = memory_get_usage(true);
|
||||
$myRequestsPerInstance = $requestsPerInstance + (mt_rand(0, 2) * 10) + mt_rand(1, 9);
|
||||
$thisPid = pcntl_fork();
|
||||
|
||||
switch ($thisPid) {
|
||||
case -1 : // error
|
||||
$cmsg = ERROR_FORK_FAILED . $thisWatcher;
|
||||
$parentLog->fatal($cmsg);
|
||||
die(getDateTime() . CON_ERROR . $res . $cmsg . $eos);
|
||||
break;
|
||||
case 0 : // child (broker daemon)
|
||||
try {
|
||||
// replace the sigcld signal handler
|
||||
pcntl_signal(SIGCLD, SIG_DFL);
|
||||
$thisPid = getmypid();
|
||||
|
||||
// create the child logger object
|
||||
/** @var gacErrorLogger $childLog */
|
||||
$childLog = new gacErrorLogger();
|
||||
|
||||
// generate a child guid for the forked child...
|
||||
$childGUID = rtrim($res, COLON) . UDASH . guid();
|
||||
|
||||
// toss the childGUID unto cache because it does not propagate down to the callback method
|
||||
gasCache::sysAdd(($groot . UDASH . $thisPid), $childGUID);
|
||||
|
||||
$queue = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG] . BROKER_QUEUE_WH;
|
||||
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
$brokerConnection = gasResourceManager::fetchResource(RESOURCE_SEGUNDO);
|
||||
if (is_null($brokerConnection)) {
|
||||
$childLog->fatal(ERROR_RESOURCE_404 . RESOURCE_SEGUNDO . COLON . BROKER_QUEUE_WH);
|
||||
consoleLog($res, CON_ERROR . ERROR_RESOURCE_404 . RESOURCE_SEGUNDO . COLON . BROKER_QUEUE_WH);
|
||||
exit(1); // shell-script exit value for fail
|
||||
}
|
||||
$brokerChannel = $brokerConnection->channel();
|
||||
// params: queue name, passive, durable, exclusive, auto-delete
|
||||
$brokerChannel->queue_declare($queue, BROKER_QUEUE_DECLARE_PASSIVE, false, false, true);
|
||||
} catch (PhpAmqpLib\Exception\AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// register the child-spawn event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_CHILD_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
SYSTEM_EVENT_KEY => SYSEV_CHILD_RPI,
|
||||
SYSTEM_EVENT_VAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $childGUID, $childLog);
|
||||
|
||||
register_shutdown_function(BROKER_SHUTDOWN_FUNCTION, $brokerChannel, $brokerConnection, $res);
|
||||
$callback = function($_request)
|
||||
{
|
||||
$startTime = gasStatic::doingTime();
|
||||
$postNormalResponse = true;
|
||||
/** @var AMQPChannel $brokerChannel */
|
||||
global $brokerChannel;
|
||||
/** @var AMQPStreamConnection $brokerConnection */
|
||||
global $brokerConnection;
|
||||
global $requestCounter, $res, $eos, $myRequestsPerInstance, $startingMemory, $groot, $service, $file;
|
||||
$event = BROKER_QUEUE_M . '(';
|
||||
$requestCounter++;
|
||||
$aryRetData = null;
|
||||
$retData = null;
|
||||
$errorStack = [];
|
||||
$request = null;
|
||||
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
|
||||
$eventSuccess = false;
|
||||
$conMsg = '';
|
||||
$eventGUID = guid();
|
||||
$thisPid = getmypid();
|
||||
$eventTimer = false; // certain events will toggle to true to log timer recording for the broker event
|
||||
$childGUID = gasCache::sysGet(($groot . UDASH . getmypid()));
|
||||
|
||||
// set-up the call-back logger
|
||||
/** @var gacErrorLogger $callBackLog */
|
||||
$callBackLog = new gacErrorLogger($eventGUID);
|
||||
|
||||
try {
|
||||
if (!firstPassPayloadValidation($_request, $service, $msg, $request, $eventGUID)) {
|
||||
$conMsg = $msg;
|
||||
$callBackLog->info($msg);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FAIL, null, $msg, null]);
|
||||
$event .= ERROR_DATA_VALIDATION_FIRST_PASS . ')';
|
||||
} elseif (!validateMetaData($request, $errorStack)) {
|
||||
for ($index = 0, $last = count($errorStack); $index < $last; $index++) {
|
||||
$conMsg .= $errorStack[$index] . $eos;
|
||||
$callBackLog->error($errorStack[$index]);
|
||||
}
|
||||
$conMsg = rtrim($conMsg, $eos);
|
||||
$aryRetData = buildReturnPayload([false, STATE_META_ERROR, $errorStack, null, null]);
|
||||
$event .= ERROR_META_VALIDATION_SECOND_PASS . ')';
|
||||
} else {
|
||||
$event .= $request[BROKER_REQUEST] . ')';
|
||||
if (is_null($request)) {
|
||||
consoleLog($res, CON_ERROR, ERROR_REQUEST_404);
|
||||
}
|
||||
|
||||
switch ($request[BROKER_REQUEST]) {
|
||||
case BROKER_REQUEST_SHUTDOWN :
|
||||
$_request->delivery_info[BROKER_CHANNEL]->basic_cancel($_request->delivery_info[BROKER_DELIVERY_TAG]);
|
||||
$conMsg = SUCCESS_SHUTDOWN;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, BROKER_REQUEST_SHUTDOWN, null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
// test broker responsiveness
|
||||
case BROKER_REQUEST_PING :
|
||||
$conMsg = SUCCESS_PING . BROKER_QUEUE_WH;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, (SUCCESS_PING . BROKER_QUEUE_WH), null]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_PEDIGREE :
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_PEDIGREE;
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, null, gasConfig::getPedigree()]);
|
||||
$eventSuccess = true;
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_WAREHOUSE :
|
||||
$eventSuccess = false;
|
||||
$eventTimer = false;
|
||||
|
||||
$objMigrate = new gacMigrations($request[BROKER_DATA], $request[BROKER_META_DATA], EVENT_WAREHOUSE);
|
||||
if (!$objMigrate->status) {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([false, $objMigrate->state, $objMigrate->errorStack, null]);
|
||||
} else {
|
||||
$guid = $objMigrate->objWarehouseMeta->getColumn(DB_TOKEN);
|
||||
// validate return guid
|
||||
if (!validateGUID($guid)) {
|
||||
$conMsg = ERROR_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([ false, FAIL_EVENT, $objMigrate->errorStack, ERROR_BROKER_REQUEST_FAILED]);
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$aryRetData = buildReturnPayload([true, SUCCESS_EVENT, $objMigrate->errorStack, $guid]);
|
||||
$eventSuccess = true;
|
||||
}
|
||||
// send the guid back to the calling client now so we can resume the warehousing...
|
||||
postResponse($aryRetData, $_request, $callBackLog, $res);
|
||||
$postNormalResponse = false;
|
||||
|
||||
// dive back into the objMigration class and perform the warehouse request
|
||||
if (!$objMigrate->whData()) {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
} else {
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_WAREHOUSE;
|
||||
$eventSuccess = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BROKER_REQUEST_REMOTE_FETCH :
|
||||
$eventTimer = true;
|
||||
$errors = [];
|
||||
/** @var gacMongoDB $tmpObj */
|
||||
if (is_null($tmpObj = grabWidget($request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$callBackLog->error($error);
|
||||
} else {
|
||||
$tmpObj->_fetchRecords($request[BROKER_DATA]);
|
||||
if ($tmpObj->status) {
|
||||
$eventSuccess = true;
|
||||
$tmpObj->eventMessages[] = STRING_REC_COUNT_RET . $tmpObj->recordsReturned;
|
||||
$conMsg = SUCCESS_EVENT . BROKER_REQUEST_FETCH;
|
||||
$queryMeta = [
|
||||
STRING_REC_COUNT_RET => $tmpObj->recordsReturned,
|
||||
STRING_REC_COUNT_TOT => $tmpObj->recordsInCollection
|
||||
];
|
||||
// recordsInQuery is a PDO thing so let's see if it exists in the class object
|
||||
if (isset($tmpObj->recordsInQuery) and $tmpObj->recordsInQuery) {
|
||||
$queryMeta[STRING_REC_COUNT_QUERY] = $tmpObj->recordsInQuery;
|
||||
}
|
||||
if (isset($request[BROKER_META_DATA][META_DONUT_FILTER]) and $request[BROKER_META_DATA][META_DONUT_FILTER] == 1) {
|
||||
$queryResults = $tmpObj->getData();
|
||||
} elseif ($tmpObj->useCache or (isset($request[BROKER_META_DATA][META_DO_CACHE]) and $request[BROKER_META_DATA][META_DO_CACHE])) {
|
||||
// todo - this is supposed to return the list of cache keys, or the single reference cache key - fix!
|
||||
$queryResults = $tmpObj->cacheMap;
|
||||
} else {
|
||||
$queryResults = $tmpObj->getData();
|
||||
}
|
||||
$retData = [STRING_QUERY_RESULTS => $queryResults, STRING_QUERY_DATA => $queryMeta];
|
||||
$aryRetData = buildReturnPayload([true, STATE_SUCCESS, $tmpObj->eventMessages, $retData]);
|
||||
} else {
|
||||
$conMsg = FAIL_EVENT . BROKER_REQUEST_FETCH;
|
||||
$aryRetData = buildReturnPayload([false, $tmpObj->state, $tmpObj->eventMessages, null]);
|
||||
}
|
||||
if (is_object($tmpObj)) $tmpObj->__destruct();
|
||||
unset($tmpObj);
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
$msg = ERROR_EVENT_404 . $request[BROKER_REQUEST];
|
||||
$conMsg = $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_DOES_NOT_EXIST, $msg, null]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $t->getMessage(), $errorStack]);
|
||||
}
|
||||
|
||||
// ensure we have a return-payload and a console message
|
||||
if (empty($aryRetData) and $postNormalResponse) {
|
||||
$msg = ERROR_NO_RET_DATA . '-' . __FILE__ . '-' . $request[BROKER_REQUEST];
|
||||
$conMsg = BROKER_QUEUE_M . ' - ' . $msg;
|
||||
$aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, null, $msg, null]);
|
||||
} elseif ($eventSuccess and empty($conMsg)) {
|
||||
$callBackLog->warn(ERROR_NO_CON_MSG);
|
||||
$conMsg = $request[BROKER_REQUEST] . ' - ' . STATE_SUCCESS;
|
||||
}
|
||||
|
||||
// prepare and send the return payload if we've not already sent it...
|
||||
if ($postNormalResponse)
|
||||
postResponse($aryRetData, $_request, $callBackLog, $res);
|
||||
|
||||
// if the event processing failed, reject the message, otherwise ack removing it from the queue
|
||||
// todo: core-452: publish the event payload to the sysEvent broker to capture the failed event
|
||||
|
||||
consoleLog($res, (($eventSuccess) ? CON_SUCCESS : CON_ERROR), $conMsg . sprintf(ERROR_EVENT_COUNT,$requestCounter, $myRequestsPerInstance));
|
||||
unset($msg);
|
||||
|
||||
// publish event metrics if we've toggled the switch on
|
||||
if ($eventTimer) {
|
||||
// get the broker-event processing time
|
||||
$eventTime = gasStatic::doingTime($startTime);
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_EVENT_TIMER,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_TIMER => $eventTime,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_META_DATA => $request[BROKER_META_DATA],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
if (!empty($childGUID)) $data[SYSTEM_EVENT_OGUID] = $childGUID;
|
||||
@postSystemEvent($data, $childGUID, $callBackLog);
|
||||
}
|
||||
|
||||
// exit the child if we've reached the request limit
|
||||
if ($requestCounter >= $myRequestsPerInstance) {
|
||||
if (getmypid() == $thisPid) {
|
||||
$meta = [
|
||||
META_SESSION_IP => STRING_SESSION_HOME,
|
||||
META_SESSION_DAEMON => 1,
|
||||
META_SESSION_MISC => INFO_BROKER_RECYCLE,
|
||||
META_EVENT_GUID => $eventGUID
|
||||
];
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_BROKER_RECYCLE,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_BROKER_GUID => $childGUID,
|
||||
DB_EVENT_GUID => $eventGUID,
|
||||
SYSTEM_EVENT_START => $startingMemory,
|
||||
SYSTEM_EVENT_PEAK => memory_get_peak_usage(true),
|
||||
SYSTEM_EVENT_END => memory_get_usage(true),
|
||||
SYSTEM_EVENT_BROKER_EVENT => $event,
|
||||
SYSTEM_EVENT_COUNT => $requestCounter,
|
||||
SYSTEM_EVENT_COUNT_TOTAL => $myRequestsPerInstance,
|
||||
SYSTEM_EVENT_META_DATA => $meta,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__
|
||||
];
|
||||
@postSystemEvent($data, $eventGUID, $callBackLog);
|
||||
}
|
||||
consoleLog($res, CON_SYSTEM, INFO_BROKER_REQ_COUNT);
|
||||
if (is_object($brokerChannel)) $brokerChannel->close();
|
||||
if (is_object($brokerConnection)) $brokerConnection->close();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
consoleLog($res, CON_SYSTEM, sprintf(INFO_BROKER_QUEUE_ESTABLISHED, BROKER_QUEUE_WH, $thisPid, $myRequestsPerInstance));
|
||||
$brokerChannel->basic_qos(null, 1, null);
|
||||
$brokerChannel->basic_consume($queue, '', false, false, false, false, $callback);
|
||||
while (count($brokerChannel->callbacks)) {
|
||||
try {
|
||||
$brokerChannel->wait();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $file, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1 : // parent
|
||||
// does nothing
|
||||
break;
|
||||
}
|
||||
return($thisPid);
|
||||
}
|
||||
|
||||
for ($numBrokers = 0; $numBrokers < $runningBrokers; $numBrokers++) {
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(INFO_BROKER_PARENT_STARTED, count($childrenPidList), BROKER_QUEUE_WH));
|
||||
|
||||
// "register" the broker instantiation event
|
||||
$data = [
|
||||
SYSTEM_EVENT_NAME => SYSEV_NAME_GROOT_REG,
|
||||
SYSTEM_EVENT_TYPE => SYSEV_TYPE_BROKER,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => $groot,
|
||||
SYSTEM_EVENT_KEY => STRING_NUMBER_CHILDREN,
|
||||
SYSTEM_EVENT_VAL => $numberChildren,
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . COLON . __LINE__,
|
||||
SYSTEM_EVENT_NOTES => BROKER_SYSEV_REG . rtrim($res, ": ")
|
||||
];
|
||||
@postSystemEvent($data, $groot, $parentLog);
|
||||
|
||||
// the parent process continues to run, waking-up every second to monitor it's children...
|
||||
// when a child dies, it's death-rattle is caught and the child is replaced with a new process.
|
||||
while (count($childrenPidList)) {
|
||||
$lastPid = 0;
|
||||
$newPidList = null;
|
||||
$result = pcntl_waitpid(0, $status); // detect any sigchld from the parent-group
|
||||
if (in_array($result, $childrenPidList)) {
|
||||
$key = array_search($result, $childrenPidList);
|
||||
array_splice($childrenPidList, $key, 1);
|
||||
// process has already exited -- restart it
|
||||
$childrenPidList[] = forkMe();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user