Why celery did't process the message and delete it? - php

I'm using php to send the message to rabbitmq and a python consumer to process it.
Here is what I did.
This part send a json to rabbitmq.
$data = array(
'id' => 123,
'url' => 'baidu.com',
);
$msg = new AMQPMessage(json_encode($data));
$channel->basic_publish($msg, $exchange);
And this part receive the message and process it (using celery).
#app.task
def mytask(json_obj):
print(json_obj)
data = json.loads(json_obj)
thread_id = data['id']
url = data['url']
return py_read(thread_id, url)
Here is what I get from the console:
[2014-09-29 15:51:34,564: WARNING/MainProcess] celery#mickey-Thurley ready.
[2014-09-29 15:51:37,395: WARNING/MainProcess] Received and deleted unknown message. Wrong destination?!?
The full contents of the message body was: body: '{"id":123,"url":"baidu.com"}' (28b)
{content_type:None content_encoding:None
delivery_info:{'redelivered': False, 'routing_key': '', 'exchange': 'celery', 'delivery_tag': 1, 'consumer_tag': '4'} headers={}}
I'm sure that the consumer received the message, but why the message didn't be processd? and what should I do to deal with it?

A Celery task is not simply data. You also need to have something that tells the worker what task you are actually calling, and that's missing from your message.
Rather than trying to implement this yourself, you should probably use one of the Celery PHP implementations that are out there, such as this one.

Related

aws-sdk-php v3.44 fails to sendMessage to SQS FIFO Queue: MessageGroupId missing?

I am using the Amazon SDK for PHP version 3.44 (released 2017-11-30). I can connect to my Amazon SQS account and execute the listQueues(), getQueueUrl(), getQueueAttributes(), and receiveMessage() commands just fine. However, the sendMessage() command consistently fails with the following message:
The request must contain the parameter MessageGroupId.
I am most definitely including this parameter. It doesn't seem to matter which version of the aws-sdk-php API I use, this message keeps coming back. Here is my code:
$queue = SqsClient::factory([
'profile' => $profile,
'region' => $region,
'version' => '2012-11-05',
'credentials' => $credentials,
]);
$queue_list = $queue->listQueues(); // ok
$url = $queue->getQueueUrl(['QueueName'=>$queue_name]); // ok
$received = $queue->receiveMessage(['QueueUrl'=>$url->get('QueueUrl')]); // ok
$response = $queue->sendMessage([
'MessageBody' => $message,
'MessageGroupId' => $message_group_id,
'QueueUrl' => $url->get('QueueUrl'),
]); // fails with message indicating MessageGroupId is missing
I have spent several hours searching for a working example of sending a message up to an Amazon SQS FIFO queue through the PHP SDK, and am beginning to believe this is not possible. Has anybody out there been able to get the aws-sdk-php library to work with an SQS FIFO queue?
The first line is creating an instance of SqsClient, not creating a SQS queue. You still still need to call $queue->createQueue. See the documentation. For fifo queues, you will need to enable "FifoQueue" to "true", and set up the "ContentBasedDeduplication" when creating the queue. When you send your message, depending on the ContentBasedDeduplication setting of the queue you created, you may or may not also need to send a "MessageDeduplicationId" along with the "MessageGroupId".
From your code, I can't see how you created the Queue.
Did you enable fifo queues with the property "FifoQueue" => "true"
Did you set "ContentBasedDeduplication" to "true" or "false" ?
Did you name your queue with the extension ".fifo" ?
I did all of these things, and configured my queue with ContentBasedDeduplication set to "false". When I send a message, the only other property that I'm sending that you aren't (along with the MessageGroupId) is MessageDeduplicationId. I'm able to send messages to the fifo queue just fine using sdk 3.44.
It looks like Amazon has quietly resolved whatever bug was blocking my API call. I did not change my queue settings or my code. The same API call that resulted in error messages last week now runs just fine.
I ran into this problem on 3.3.0 forever. In my case, I just needed to upgrade to 3.44.2, then pass in MessageDeduplicationId in addition to MessageGroupId. I would probably double check your SDK version if you run into this issue.

Amazon SQS service with Elastic Beanstalk

I am fairly new to Amazon SQS and I am having a hard time understanding what is going on. I set the HTTP Path to a file that could handle the requests. but I am not sure if that was the correct thing to do. What is the proper way? Why do the messages go directly to "In Flight"? What happens when the message is sent to the HTTP path? I am using php for my application, so if someone could give me guidance on what I am doing wrong, then I would greatly appreciate it!
When I check for a message with my php script that looks likes this:
$sqs_client = new SqsClient($sqs_credentials);
// Get the queue URL from the queue name.
$result = $sqs_client->getQueueUrl(array('QueueName' => "NormalPoll"));
$queue_url = $result->get('QueueUrl');
// Receive a message from the queue
$result = $sqs_client->receiveMessage(array(
'QueueUrl' => $queue_url
));
if ($result['Messages'] == null) {
die('No Message');
}
// Get the message information
$result_message = array_pop($result['Messages']);
$body = $result_message['Body'];
print $body;
I always get 'No Message' in return when running the program. I inserted a message via the AWS SQS console and I am unable to receive it. The message goes automatically to 'in flight'.
Thanks In Advance!
The messages are inflight because of the beanstalk worker environment configuration.
The following documentation provides details on how to configure a beanstalk worker environment.
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html

PHP Azure SDK Service Bus returns Malformed Response

I'm working on trace logger of sorts that pushes log message requests onto a Queue on a Service Bus, to later be picked off by a worker role which would insert them into the table store. While running on my machine, this works just fine (since I'm the only one using it), but once I put it up on a server to test, it produced the following error:
HTTP_Request2_MessageException: Malformed response: in D:\home\site\wwwroot\vendor\pear-pear.php.net\HTTP_Request2\HTTP\Request2\Adapter\Socket.php on line 1013
0 HTTP_Request2_Response->__construct('', true, Object(Net_URL2)) D:\home\site\wwwroot\vendor\pear-pear.php.net\HTTP_Request2\HTTP\Request2\Adapter\Socket.php:1013
1 HTTP_Request2_Adapter_Socket->readResponse() D:\home\site\wwwroot\vendor\pear-pear.php.net\HTTP_Request2\HTTP\Request2\Adapter\Socket.php:139
2 HTTP_Request2_Adapter_Socket->sendRequest(Object(HTTP_Request2)) D:\home\site\wwwroot\vendor\pear-pear.php.net\HTTP_Request2\HTTP\Request2.php:939
3 HTTP_Request2->send() D:\home\site\wwwroot\vendor\microsoft\windowsazure\WindowsAzure\Common\Internal\Http\HttpClient.php:262
4 WindowsAzure\Common\Internal\Http\HttpClient->send(Array, Object(WindowsAzure\Common\Internal\Http\Url)) D:\home\site\wwwroot\vendor\microsoft\windowsazure\WindowsAzure\Common\Internal\RestProxy.php:141
5 WindowsAzure\Common\Internal\RestProxy->sendContext(Object(WindowsAzure\Common\Internal\Http\HttpCallContext)) D:\home\site\wwwroot\vendor\microsoft\windowsazure\WindowsAzure\Common\Internal\ServiceRestProxy.php:86
6 WindowsAzure\Common\Internal\ServiceRestProxy->sendContext(Object(WindowsAzure\Common\Internal\Http\HttpCallContext)) D:\home\site\wwwroot\vendor\microsoft\windowsazure\WindowsAzure\ServiceBus\ServiceBusRestProxy.php:139
7 WindowsAzure\ServiceBus\ServiceBusRestProxy->sendMessage('<queuename>/mes…', Object(WindowsAzure\ServiceBus\Models\BrokeredMessage)) D:\home\site\wwwroot\vendor\microsoft\windowsazure\WindowsAzure\ServiceBus\ServiceBusRestProxy.php:155
⋮
I've seen previous posts that describe similar issues; Namely:
Windows Azure PHP Queue REST Proxy Limit (Stack Overflow)
Operations on HTTPS do not work correctly (GitHub)
That imply that this is a known issue regarding the PHP Azure Storage libraries, where there are a limited amount of HTTPS connections allowed. Before requirements were changed, I was accessing the table store directly, and ran into this same issue, and fixed it in the way the first link describes.
The problem is that the Service Bus endpoint in the connection string, unlike Table Store (etc.) connection string endpoints, MUST be 'HTTPS'. Trying to use it with 'HTTP' will return a 400 - Bad Request error.
I was wondering if anyone had any ideas on a potential workaround. Any advice would be greatly appreciated.
Thanks!
EDIT (After Gary Liu's Comment):
Here's the code I use to add items to the queue:
private function logToAzureSB($source, $msg, $severity, $machine)
{
// Gather all relevant information
$msgInfo = array(
"Severity" => $severity,
"Message" => $msg,
"Machine" => $machine,
"Source" => $source
);
// Encode it to a JSON string, and add it to a Brokered message.
$encoded = json_encode($msgInfo);
$message = new BrokeredMessage($encoded);
$message->setContentType("application/json");
// Attempt to push the message onto the Queue
try
{
$this->sbRestProxy->sendQueueMessage($this->azureQueueName, $message);
}
catch(ServiceException $e)
{
throw new \DatabaseException($e->getMessage, $e->getCode, $e->getPrevious);
}
}
Here, $this->sbRestProxy is a Service Bus REST Proxy, set up when the logging class initializes.
On the recieving end of things, here's the code on the Worker role side of this:
public override void Run()
{
// Initiates the message pump and callback is invoked for each message that is received, calling close on the client will stop the pump.
Client.OnMessage((receivedMessage) =>
{
try
{
// Pull the Message from the recieved object.
Stream stream = receivedMessage.GetBody<Stream>();
StreamReader reader = new StreamReader(stream);
string message = reader.ReadToEnd();
LoggingMessage mMsg = JsonConvert.DeserializeObject<LoggingMessage>(message);
// Create an entry with the information given.
LogEntry entry = new LogEntry(mMsg);
// Set the Logger to the appropriate table store, and insert the entry into the table.
Logger.InsertIntoLog(entry, mMsg.Service);
}
catch
{
// Handle any message processing specific exceptions here
}
});
CompletedEvent.WaitOne();
}
Where Logging Message is a simple object that basically contains the same fields as the Message Logged in PHP (Used for JSON Deserialization), LogEntry is a TableEntity which contains these fields as well, and Logger is an instance of a Table Store Logger, set up during the worker role's OnStart method.
This was a known issue with the Windows Azure PHP, which hasn't been looked at in a long time, nor has it been fixed. In the time between when I posted this and now, We ended up writing a separate API web service for logging, and had our PHP Code send JSON strings to it over cURL, which works well enough as a temporary work around. We're moving off of PHP now, so this wont be an issue for much longer anyways.

RabbitMq: Replace duplicated messages

I'm using RabbitMq for submitting data for registered web hooks.
base info:
If a contact is created in the system, the message is put in the queue and the consumer is sending later the hook data to the registered url.
To my question:
Its possible, that a contact is updated in 5 seconds twice and that both messages are still in the queue.
But I'd like, if the second message is queued, that the first message will be removed.
I know that i can't delete the message manually. But is it somehow possible to set an id on the message and if two messages with the same id are in the same queue, that the first one is automatically removed/replaced?
That only one request is sent to the url. I know you can set a message id on the message self. But I have nothing found to replace the old one.
My PHP Code (simplified):
$connection = new AMQPConnection('localhost', 5672, 'test', 'test');
$channel = $connection->channel();
$channel->queue_declare(self::QUEUE_NAME, false, true, false, false);
$data = array(
'model' => get_class($subject),
'id' => $subject->getId(),
'event' => $event->getName()
);
$messageProperties = array(
'message_id' => get_class($subject) . '-' . $subject->getId()
);
$channel->basic_publish(new AMQPMessage(json_encode($data), $messageProperties), '', self::QUEUE_NAME);
$channel->close();
$connection->close();
Btw i'm using the the php amqplib https://github.com/videlalvaro/php-amqplib.
Thanks for the help
Flo
RabbitMQ doesn't delete/filter messages that way. You have to do that at the app level, probably using something like a bloom filter.
You could potentially tag each message with a unique message ID. A consuming application should keep an optimised list of inbound message IDs that it has already processed (in a thread-safe HashMap (Java), or Dictionary (.NET) implementation.
Should a message arrive, that has already been processed (the message ID is present in the stored list of handled message IDs), it will be ignored (or a polite “please wait” style response should be issued), preserving idempotency.

Keep messages from ACKing on get() using pecl-amqp

I'm attempting to use pecl-amqp for a project of mine. I'm having difficulties though with the ACK process. I need to manually ACK each message I receive off a queue, but the messages appear to be auto-ACKing when the message is retrieved.
I've set my queue to AMQP_NOACK and am using AMQPQueue->get(AMQP_NOACK) but none of it seems to have any affect, the messages are still removed from the queue without me sending AMQPQueue->ack().
If anyone has any experience with the pecl-amqp I would appreciate the help.
I have been having the same problem but have managed to get the acknowledge mechanism to work using the consume method. Using rabbitmqctl to list the entries in the queue it appears to work OK, though I seems to be getting the messages off the queue in a different order to that in which they were sent - which kind of defeats the object of a queue. My code is as follows:
// Create the queue to be:
// AMQP_DURABLE - messages will withstand a broker restart (i.e. they are written to disk).
// AMQP_NOACK - when consumed messages will not be marked as delivered until an explicit ACK is received.
$q->declare($queueName, AMQP_DURABLE | AMQP_NOACK );
// Bind it on the exchange to routing key.
$q->bind($exchangeName, $routingKey);
// Set the options for our consumption of the messages:
// Get a minimum of 0 msg.
// Get a maximum of 1 msg.
// Don't ACK the message on consumption i.e. explicitly acknoledge later.
$options = array(
'min' => 0,
'max' => 1,
'ack' => false
);
// Get the messages
$results_array = $q->consume($options);
// show the message
print_r($results_array);
$delivery_tag = $results_array[0]['delivery_tag'];
echo 'delivery_tag: [' . $delivery_tag . "].\r\n";
// Acknowledge receipt of the message.
$q->ack($delivery_tag);
For reference, the AMQP extension did not support the AMQP_NOACK correctly. You can get it to do what you want, but it isnt pretty. I am working on fixing that now. FYI, AMQP_NOACK means that you will not have to come back to acknowledge the message later, i.e. as soon as the server sends the message to the client, the server marks the message as ack'ed. There has been some confusion around this, so I wanted to clarify.

Categories