Zend Queue with MySql …

… because life isn’t already hard enough.

If you are a masochist (or your boss is a sadist(*); or your project made you one; or you have the ambition to be so) and need to set up job queues through Zend Framework with a MySQL database. Here’s how it’s done.

Precursor: finding any practical information/tutelage about Zend_Queue is nearly impossible. The documentation is complete shite – sorry; it just is.  After fiddling around with it, I finally have a working model. Thought it worthy of ye good ‘ol fashion blog post.

Before you start, you’ll need to have a database available and add two new tables. You can hunt for the necessary DDL in the framework itself or just visit the source.

Let’s make sure we have the configuration set up correct. Notice the queue settings here.

For this example, I’m going to assume you are working in a fresh Zend Framework project. Even if you’re not — and God bless your soul if that’s true — it should be simple enough to figure out how the bits fit together.

; file: application/configs/application.ini

[production]
; ...
resources.frontController.params.displayExceptions = 0
; ...
queue.driverOptions.type = "pdo_mysql"
queue.driverOptions.host = "localhost"
queue.driverOptions.username = "howtoqueue"
queue.driverOptions.password = "howtoqueue"
queue.driverOptions.dbname = "howtoqueue"

Next, let’s do some initialization in the bootstrap:

<?php

// file: application/Bootstrap.php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
  /**
   * Set up the queue
   *
   */
  protected function _initQueue()
  {
    $options = $this->getOptions();

    // Create an adapter for our queue and register it.
    $queueAdapter = new Zend_Queue_Adapter_Db( $options[ 'queue' ] );
    Zend_Registry::getInstance()->queueAdapter = $queueAdapter;

  }

}

Zend_Queue_Adapter_Db is pretty straight-forward. It’s the marshal of the Queue that we’re about to work with.

Sticking with simple, I’m going to use a very simple class to contain data for emails. This is exactly the problem I was facing earlier today: in-process emailing sucks balls. Adding a queue sucks balls just a little bit less (it dials your snafu-potentiometer up a notch, etc.) I needed a plug-in solution that JFW; here’s the nitwit POPO:

<?php

// file: library/EmailPopo.php

/**
 * Detractors beware: I already know this is stupid.
 * Keep insults at only the most personal level.
 */
class EmailPopo
{
  // The stuff
  private $_data = array();

  // Get something from the stuff
  public function __get($key) {
    return $this->_data[$key];
  }

  // Add something to the stuff
  public function __set($key, $value) {
    $this->_data[$key] = $value;
  }

}

Now that we have all the ingredients in place to post something to our queue, let’s do something about it.

// file: application/controllers/IndexController.php

require_once "EmailPopo.php";
public function indexAction()
{
  // Get the queue adapter
  $queueAdapter = Zend_Registry::getInstance()->queueAdapter;

  // Get a queue we can smack around
  $options = array( 'name' => 'emailqueue' );
  $queue = new Zend_Queue( $queueAdapter, $options );

  // Create a silly email
  $email = new EmailPopo();
  $email->date = time();
  $email->from = "[email protected]";
  $email->to = "[email protected]";
  $email->subject = "I want a divorce";
  $email->body = "Letter's in the mail.";

  // serialize and shrink the POPO
  $message = base64_encode( gzcompress( serialize( $email ) ) );

  // Send it.
  $queue->send( $message );

}

There’s nothing really special happening there. We create our email instance, plop in the details, zip it up and submit it to the queue. Poop simple.

Finally, here’s how to extract the messages:

// file: application/controllers/IndexController.php

public function queueAction() {

  // Get the queue adapter
  $queueAdapter = Zend_Registry::getInstance()->queueAdapter;

  // Grab the email queue
  $options = array( 'name' => 'emailqueue' );
  $queue = new Zend_Queue( $queueAdapter, $options );

  // Read 2 messages.
  $messages = $queue->receive( 2 );
  foreach( $messages as $message ) {

    try {
      // Decompose the email
      $email = unserialize( gzuncompress( base64_decode( $message->body ) ) );

      // see what happens when something goes snafu...
      //throw new Exception( "testing failure" );

      // ************************
      //
      // Do your magic here
      //
      // ************************

      // All's well, we can just delete the job
      $queue->deleteMessage( $message );

      echo sprintf(
        "Sent email to %s (time: %s)<br/>",
        $email->to,
        new Zend_Date( $email->date )
        ); 

    } catch( Exception $ex ) {
      echo "Kaboom!: " . $ex->getMessage() . "<br/>";

      // At this point, the message is still
      // available in the DB but will not
      // be processed by future receive()'s

    }

  }

  die( "Done" );

}

For the record, after running through the loops to get this working, I realized that Zend_Queue was a complete overkill for the task at hand.  Having been away from PHP for a while, I see why I left. The folks behind these tools mean well, but what a mess. What a bloody, bloody mess.

Fin

 Grab the source …

 

(*) Slavko: a masochistic boss would be a perfect boss. Corrected.

Tagged with:
Posted in The IT Life

Leave a Reply

Error: Twitter did not respond. Please wait a few minutes and refresh this page.