Using Beanstalkd to Schedule the release of a post in Laravel

Posted: 2014-05-19 19:12:09

Phase 1 of my master plan is to regularly write more posts on misc web and coding in general related topics. And sometimes I can sit and write a few of them but it would be best not to release them all at once for a lot of reason.

So this will cover the way I setup a schedule feature to my post creation process. Yes there are libraries for this but I just wanted to have fun making this feature. There are three key posts that helped me get through this.

I will not repeat what they offer but link to them as needed.

We will cover

  • Setup up a schedule field
  • Setting up a Beanstalkd server

Setting up the field

My Post model has a published or active field and now a scheduled field. It is just a timestamp format field. I could have done other solutions and tighten this up a bit so any feedback is welcome below. When making a post I have two options at the bottom.

I also use the Timepicker addon

Schedule Options

If the new post is not Active && has a Scheduled date then this method kicks into place in my Posts controller during the creation process. I will most likely move this to a Service or Model since it really is not the job of the Controller but this is v1 of my idea.

//app/controllers/PostsController.php

       public function __construct(MarkdownExtraParser $mk = null, SchedulerAls $scheduler = null)
        {
          //other code here
          $this->scheduler    = ($scheduler == null) ? new SchedulerAls() : $scheduler;
        }

    /**
     * Store a newly created post in storage.
     *
     * @return Response
     */
    public function store()
    {
          //basic code here for laravel
          $this->scheduler->sendToQueue($post);

First

The SchedulerAls Class is pretty simple, using the Laravel Queue

The sendToQueue($post) method just does that

//app/Als/Services/SchedulerAls.php

class SchedulerAls

public function sendToQueue($post) {
        if(!empty($post->scheduled)) {
            \Log::info("Testing: PushJob {$post->id}");
            \Queue::push('Als\Services\SchedulerAls', array('post' => $post->id));
        }
  }

This adds a row to the queue to check the "Als\Services|SchedulerAls" class and trigger the fire method (more on that below) passing it the $post->id.

I make my fire method call to a processPost method that decides if this post is not active and if it has a date set. If so and that date is not greater than today make it active else release it for 30 minutes and the next command needed into the queue.

Eg if I post 1 for tomorrow (#100) and after that one for today (#101), it will see #100 is not ready and move on to #101.

Here is that the fire method and the processPost. Really it can all be in the fire method.

//app/Als/Facades/Services/SchedulerAls.php
class SchedulerAls {

    public function fire($job, $data)
    {
        $this->processPost($job, $data);
    }

    protected function processPost($job, $data)
    {
        $id = $data['post'];
        $post = \Post::find($id);
        $scheduled = Carbon::createFromFormat('Y-m-d H:i:s', $post->scheduled);
        $now = Carbon::create();

        if($scheduled->lt($now)) {
            $post->active = 1;
            $post->save();
            $job->delete();
        } else {
            $job->release(30);
        }
    }

So that is it really. Set to active or not. Delete job or release it back to the queue with a 30 minute delay etc.

Setting up the server.

This was really not bad. I ended up using the existing server but will move to another server shortly. One thing to keep in mind is your firewall. You really want to make sure that you are only allowing certain IPs to visit this server or limit beanstalkd to localhost.

As noted this tutorial handles most of this really well Fideloper

Finally beanstalk console is a great way, especially locally if you are not using "sync" driver to see what is going on. Just make sure to block it with htaccess so no one can just visit it on your server.

That is about it. Later I will add an even to allow other things to be triggered maybe via IFTT!


Tags:

laravel php queue