I am using the messenger component in a Symfony application to process messages from rabbitmq.
When I send a 2-3mb message and an error occurs in my handler, the middleware that tries to send the message back to rabbit raises an exception of type:
AMQPException Library error: table too large for buffer
I found similar error in this links :
https://github.com/vyuldashev/laravel-queue-rabbitmq/issues/10
https://github.com/alanxz/rabbitmq-c/issues/224
https://github.com/php-amqp/php-amqp/issues/131
But I don't see any solution or workaround provided!
I found a workaround: when the message is being redirected back to queue (to retry later) one huge stamp is being added
In my serializer, in method 'encode' I filter stamps:
$allStamps = [];
foreach ($envelope->all() as $stampKey => $stamps) {
if ($stampKey === 'Symfony\Component\Messenger\Stamp\ErrorDetailsStamp') {
// this header could be huge and drasticaly increase a size of a message
continue;
}
$allStamps = array_merge($allStamps, $stamps);
}
return [
'body' => serialize($messageBody),
'headers' => [
// store stamps as a header - to be read in decode()
'stamps' => serialize($allStamps),
],
];
Related
I'm using the symfony messenger component : https://symfony.com/doc/current/messenger.html
But my logs are flooded by these messages when retries are failing :
16:14:31 CRITICAL [messenger] Error thrown while handling message AppBundle\Message\NewsletterMessage. Removing from transport after 3 retries. Error: "No newsletter subscriber found" ["message" => AppBundle\Message\NewsletterMessage^ { …},"class" => "AppBundle\Message\NewsletterMessage","retryCount" => 3,"error" => "No newsletter subscriber found","exception" => Symfony\Component\Messenger\Exception\HandlerFailedException^ { …}]
The thing is that I don't want critical messages: is there a way to change them into error messages ?
Found in the file :
Symfony\Component\Messenger\EventListener\SendFailedMessageForRetryListener
the responsible line at l.76 :
$this->logger->critical('Error thrown while handling message {class}. Removing from transport after {retryCount} retries. Error: "{error}"', $context + ['retryCount' => $retryCount, 'error' => $throwable->getMessage(), 'exception' => $throwable]);
Hope someone can help,
Thanks ! ^^
You may use failure_transport and make some logs for example
https://symfony.com/doc/current/messenger.html#retries-failures
I am using PHP ICS Parser https://github.com/u01jmg3/ics-parser to parse up to 33 remote URL's. The Parser intermittently fails parsing some of these URL's.
The actual exception error details returned by PHP ICS are:
exception 'Exception' with message 'The file path or URL 'admin.vrbo.com/icalendar/…; does not exist.
Here's my code:
foreach($ical_props_arr as $row) {
$property_title=$row['title'];
$import_url=$row['ical_import_url'];
try {
$ical = new ICal($import_url, array(
'defaultSpan' => 2, // Default value
'defaultTimeZone' => 'UTC',
'defaultWeekStart' => 'MO', // Default value
'disableCharacterReplacement' => false, // Default value
'skipRecurrence' => false, // Default value
'useTimeZoneWithRRules' => false, // Default value
));
} catch (\Exception $e) {
$error.='An Error Occurred importing: '.$import_url."\n";
$error.=$property_title." Import ICAL URL, appears to be Bad!!\n\n";
}
}
All of the URL's are confirmed good.
Could this be a PHP timing issue, calling the multiple URL's and not waiting for the remote server to respond quick enough?
Any help would be appreciated.
Thanks
I use JFactory::getApplication()->enqueueMessage('Message goes here', 'error') to show users the request could not be processed, it works OK but Joomla orders the messages in the sequence they occur. Because my message happens before the Joomla save error is captured, the user sees this message:
you cannot do this operation //my message
Save failed with the following error: //Joomla message
I want to invert the order and have Joomla message as it is, followed by my message so that it makes sense:
Save failed with the following error: // Joomla message
you cannot do this operation // my message
Is that possible? (without language translation or overrides?)
After help from answers, I could do the inversion: 1st message is a placeholder to be searched using getMessageQueue(). Although you could delete messages in J.2.5 it is no longer possible with J.3+ (https://developer.joomla.org/joomlacode-archive/issue-33270.html). The solution is to reflect the class to unprotect the queue and replace it.
public static function reorderMessages()
{
//error messages
$err01 = JText::_('COM_COMPONENT_MESSAGE1');
//you can adapt and add other messages here
$app = JFactory::getApplication();
$new_messages = array();
$replacement_found = null;
//mirror protected $_messageQueue
$appReflection = new ReflectionClass(get_class($app));
$_messageQueue = $appReflection->getProperty('_messageQueue');
$_messageQueue->setAccessible(true);
//get messages
$messages = $app->getMessageQueue();
foreach($messages as $key=>$message)
{
if($messages[$key]['message'] == 'MESSAGE_TO_REPLACE' && $messages[$key]['type'] == 'error' )
{
$replacement_found = 1;
continue;
}
$new_messages[] = $message;
}
if($replacement_found)
{
//save all messages
$_messageQueue->setValue($app, $new_messages);
//add replacement message to the end of the queue
$app->enqueueMessage(JText::_($err01, 'error');
}
return true;
}
Be very careful where to call the function, if the message queue is empty Joomla will return an error and break your code. Make sure you have enqueued the 1st message before calling the function.
You can use getMessageQueue() on the application object (i.e., $myApp = JFactory::getApplication()) to get a copy of the message queue array. You can clear the message queue by passing true to the getMessageQueue()` function call. It will still return a copy of the system message queue array.
You could then use regex's to find the keys in the array and reorder them. I would find the system error message in the translation file, and use the error message key from the translation .ini file (instead of the actual text of the error message) for the regex search so it doesn't break if the error message changes. I'd also do it in a plugin and on a late lifecycle hook (maybe the onBeforeRender event).
You can save the modified message queue array back to the JApplication class instance using the application object's enqueueMessage() method, which has this signature:
enqueueMessage(string $msg, string $type = 'message') : void
source
I use Laravel built-in validator and I want to get the first error message
if ($validator->fails()) {
$error = $validator->messages()->toJson();
.....
}
This is the result when I print error
{"name":["The name must be at least 5 characters."],"alamat":["The address must be at least 5 characters."]}
In the example above, I want to get the first error, which is "The name must be at least 5 characters.". How can I do that?
Try this:
if ($validator->fails()) {
$error = $validator->errors()->first();
}
As per 2019 Laravel 5.8 and above to get all the error messages from the validator is as easy as this:
// create the validator and make a validation here...
if ($validator->fails()) {
$fieldsWithErrorMessagesArray = $validator->messages()->get('*');
}
You will get the array of arrays of the fields' names and error messages. Something like this:
[
'price'=>
[
0 => 'Price must be integer',
1 => 'Price must be greater than 0'
]
'password' => [
[
0 => 'Password is required'
]
]
]
You can use other validation messages getters that Illuminate\Support\MessageBag class provides (it is actually the object type that $validator->messages() above returns).
Message Bag Error Messages Additional Helpers
Go to your_laravel_project_dir/vendor/illuminate/support/MessageBag.php and find some useful methods like keys, has, hasAny, first, all, isEmpty etc. that you may need while checking for particular validation errors and customizing HTTP response messages.
It is easy to understand what they do by the look at the source code. Here is the Laravel 5.8 API reference though probably less useful than the source code.
In your ajax request, when you get the data, try data.name.
This will give you the error message for the name field.
$.ajax({
url: "/your-save-url",
type: "post",
data: serializedData,
success: function(data) { alert(data.name)}
});
If validation fails, the withErrors method can be used to flash the error messages to the session. This is an array and this method will automatically share $errors with all views after redirection.
return redirect('register')->withErrors($validator, 'login');
The MessageBag can be accessed using the instance from the $errors variable:
{{ $errors->login->first('email') }}
Form API docs
Hope this is helpful.
If you are using toastr style error displaying, this will work:
#if(session()->get('errors'))
toastr.error("{{ session()->get('errors')->first() }}");
#endif
for getting all errors, try this:
if ($validator->fails()) {
$error = $validator->errors()->all();
}
if you want to do it inside the controller you can:
Arr::first(Arr::flatten($validator->messages()->get('*')))
you will get the first text message
The email must be accepted.
While using Google Cloud Compute's API in PHP, I am able to start, stop, delete instances as well as create and delete disks.
However, when trying to create an Instance, I keep getting this error
Invalid value for field 'resource.disks'
PHP Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST https://www.googleapis.com/compute/v1/projects/project/zones/zone/instances: (400) Invalid value for field 'resource.disks': ''. Boot disk must be specified.' in /var/www/html/google/google-api-php-client/src/Google/Http/REST
Here is the request I am making
self::connectClient();
$computeService = new Google_Service_Compute($this->client);
if ($this->client->getAccessToken())
{
$googleNetworkInterfaceObj = new Google_Service_Compute_NetworkInterface();
$network = self::DEFAULT_NETWORK;
$googleNetworkInterfaceObj->setNetwork($network);
$diskObj = self::getDisk($instance_name);
$new_instance = new Google_Service_Compute_Instance();
$new_instance->setName($instance_name);
$new_instance->setMachineType(self::DEFAULT_MACHINE_TYPE);
$new_instance->setNetworkInterfaces(array($googleNetworkInterfaceObj));
$new_instance->setDisks(array(
"source"=>$diskObj->selfLink,
"boot"=>true,
"type"=>"PERSISTENT",
"deviceName"=>$diskObj->name,
));
$insertInstance = $computeService->instances->insert(self::DEFAULT_PROJECT,self::DEFAULT_ZONE_NAME, $new_instance);
Any help will be highly appreciated, thank you.
Ok the solution was really simple (and silly)
Instead of
$new_instance->setDisks(array(
"source"=>$diskObj->selfLink,
"boot"=>true,
"type"=>"PERSISTENT",
"deviceName"=>$diskObj->name,
));
It's supposed to be
$new_instance->setDisks(array(
array(
'source'=>self::getDisk($instance_name)->selfLink,
'boot'=>true,
'type' => "PERSISTENT",
'deviceName'=>self::getDisk($instance_name)->name,
)
));