How on PHP cancel consumer in RabbitMQ? - php

I have next code:
<?php
// callback function for recive the message and canceling consumer
function consumer(\AMQPEnvelope $envelope, \AMQPQueue $queue)
{
$queue->ack($envelope->getDeliveryTag());
$queue->cancel($envelope->getCorrelationId());
echo "Message was recived and consumer will be canceled by consumer tag: {$envelope->getCorrelationId()}\n";
}
// generating uniqie exchange and queue
$correlationId = uniqid(str_replace('.', '', (string)microtime(TRUE)) . '_');
$queueName = "databus_response_{$correlationId}";
$consumerTag = "consumer_tag_{$correlationId}";
// establesh connection
$connection = new \AMQPConnection(array('host'=>'127.0.0.1', 'user'=>'guest', 'password'=>'guest'));
$connection->connect();
$channel = new \AMQPChannel($connection);
// declare exchange
$exchange = new \AMQPExchange($channel);
$exchange->setFlags(AMQP_AUTODELETE);
$exchange->setType(AMQP_EX_TYPE_TOPIC);
$exchange->setName($queueName);
$exchange->declareExchange();
// declare queue
$queue = new \AMQPQueue($channel);
$queue->setFlags(AMQP_EXCLUSIVE);
$queue->setName($queueName);
$queue->declareQueue();
$queue->bind($queueName, '#');
// publish message in exchange
$exchange->publish('Test message', NULL, AMQP_PASSIVE, array('correlation_id' => $consumerTag));
// run consumer for getting this echange and canceling consumer after recive the message
$queue->consume('consumer', AMQP_NOWAIT, $consumerTag);
How you can see, i send one message to queue, and run consumer on this queue. In consumer method, you can see, what i want stop consumer on this queue after reciving first message by "cancel" method, but consumer not stopped. What i do wrong?
AMQP PECL module version 1.2.0 from https://github.com/pdezwart/php-amqp/tree/v1.2.0
PHP 5.4.4-14+deb7u10 (cli)
Linux v270 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64 GNU/Linux

just return false from consumer callback when you want to stop consuming.
From AMQPQueue.php stub file:
The AMQPQueue::consume() will not return the processing thread back to
the PHP script until the callback function returns FALSE.
P.S.: sad to say that php-amqp extension still lack of good documentation, but you can always read method annotation in stub files or read a bit outdated documentation on official php site in Polish language here - http://www.php.net/manual/pl/book.amqp.php (don't worry, nobody translated it, so all sensitive doc is in English).

Nowadays in the php-amqplib v2.* world you can also call basic_cancel on your AMQPChannel object.
here is a great blog post about controlling the number of consumers and their ttl using this technique.

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.

Using Confirms (publisher acknowledgements) with php-amqplib

I'm trying to figure out how to use Confirms (Publisher Acknowledgements) using the php-amqplib library, which is the library recommended for using RabbitMQ with PHP at http://rabbitmq.com/.
The code itself isn't very well documented and I can't find anything that mirrors the interfaces of the Java and python interfaces that I've found.
The Java example is here.
I've grepped for the various combinations of function names that I could think of in the PHP source and haven't found anything. I'm looking for something similar to:
$channel->confirm_select();
...
$channel->wait();
It looks like https://github.com/videlalvaro/php-amqplib/blob/master/PhpAmqpLib/Helper/Protocol/Protocol091.php has support for the functionality, but I don't see how it is exposed to the user.
I was looking for this today and found that php-amqplib has implemented it.
Check out this demo for details.
Here's a snippet:
$connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
$channel = $connection->channel();
$channel->set_ack_handler(
function (AMQPMessage $message) {
echo "Message acked with content " . $message->body . PHP_EOL;
}
);
$channel->set_nack_handler(
function (AMQPMessage $message) {
echo "Message nacked with content " . $message->body . PHP_EOL;
}
);
/*
* bring the channel into publish confirm mode.
* if you would call $ch->tx_select() befor or after you brought the channel into this mode
* the next call to $ch->wait() would result in an exception as the publish confirm mode and transactions
* are mutually exclusive
*/
$channel->confirm_select();
/*
name: $exchange
type: fanout
passive: false // don't check if an exchange with the same name exists
durable: false // the exchange won't survive server restarts
auto_delete: true //the exchange will be deleted once the channel is closed.
*/
$channel->exchange_declare($exchange, 'fanout', false, false, true);
$i = 1;
$msg = new AMQPMessage($i, array('content_type' => 'text/plain'));
$channel->basic_publish($msg, $exchange);
/*
* watching the amqp debug output you can see that the server will ack the message with delivery tag 1 and the
* multiple flag probably set to false
*/
$channel->wait_for_pending_acks();
Apparently neither the PECL AMQP library nor the pure php-amqplib library implement the Confirms extension. The only real solution at this point is to implement two queues to simulate acknowledgements to the publisher.
There are plans to implement Confirms in both libraries, but I don't see any movement in either.

Pubnub PHP Subscribe Function

I need major help!
I am having troubles getting the Pubnub subscribe function to work with PHP! I can get the publish function to work, but not the subscribe function. I have copied some code straight from the Pubnub site, but I am not getting anything. Any help? Also, my PHP version is 5.2.*.
Code:
<?
include("Pubnub.php");
$pubnub = new Pubnub(
"not showing you", // PUBLISH_KEY
"not showing you", // SUBSCRIBE_KEY
"", // SECRET_KEY
false // SSL_ON?
);
$pubnub->subscribe(array(
'channel' => 'Chat',
'callback' => create_function(
'$message',
'var_dump($message); return true;'
)
));
?>
⚠️ ALERT: SDK has been upgraded ⚠️
New SDK URL: https://github.com/pubnub/php
You are asking about a way to use the Subscribe method within a web server like Apache using PHP as the dynamic processing language. Note that this is not a good practice and generally not necessary to do. You would not use the Subscribe({...}) method in a request/response.
The correct way to utilize the $pubnub->subscribe(...) method is in a long-lived PHP process, not involving a web server request-response model. Here are some examples that are confirmed to work:
https://github.com/pubnub/php
Note that each example is assumed to be in a solitary PHP process outside of a web server like Apache when using the Subscribe API in PHP. However! The Publish() API can be used anywhere, including an Apache web server.
Reading History w/ Apache PHP
As an alternative you will be happy to take advantage of our HISTORY API. You can query messages in the Queue with this and receive messages. Here is an example PHP History API usage:
<?php
## Capture Publish and Subscribe Keys from Command Line
$publish_key = "YOUR_PUBLISH_KEY";
$subscribe_key = "YOUR_SUBSCRIBE_KEY";
## Require Pubnub API
require('../Pubnub.php');
## -----------------------------------------
## Create Pubnub Client API (INITIALIZATION)
## -----------------------------------------
$pubnub = new Pubnub( $publish_key, $subscribe_key );
## Get History
echo("Requesting History...\n");
$messages = $pubnub->history(array(
'channel' => 'hello_world', ## REQUIRED Channel to Send
'limit' => 100 ## OPTIONAL Limit Number of Messages
));
var_dump($messages); ## Prints Published Messages.
?>
The php subscribe function is broken and will be fixed in a new upcoming api, I talked with support recently about this and they gave me the this information.

Categories