Blog

Updating PingMe's Scheduling System

Posted: Jan 07, 2008 by Billy Gray Tagged

Over the last few months we’ve put a lot of work into PingMe‘s scheduling system because it was necessary if we wanted to expand the service and make it more reliable. Before I get into what we are doing differently I’ll take a moment to describe the previous situation and our setup.

PingMe has a number of daemons – independent processes that are always running, scheduling pings, sending them out, and processing messages that you send to the service. These daemons are implemented in Ruby using Ruby On Rails. This allows them to be tightly coupled with the PingMe web application – the daemon processes and the webapp operate with the same model, which helps us keep the code pretty clean.

The ones of most concern are the dispatchers, the daemons who’s job it was to check for new pings to deliver, and then reschedule them for the next delivery (if necessary). Getting the concurrency right was rather tricky and involved some real nerding out in Postgres (our database engine of choice). Basically, the dispatchers had to do what’s called mutex locking in order to guarantee that different dispatchers would try to send out the same message. The locking code is a neat trick, btw, and it’s still in use, it’s served us well:

  def acquire_mutex
    ActiveRecord::Base.connection.execute(
    <<-END_OF_SQL
      LOCK mutex IN ACCESS EXCLUSIVE MODE;
    END_OF_SQL
    )
  end

Different database engines have different facilities for this sort of thing, but basically doing this within a transaction caused the other dispatchers to wait until the lock was released. What were they waiting for? A chance to grab a block of pings to dispatch.

Now the rescheduling of pings, and the scheduling of pings was honestly a not very clean thing to begin with. We had callbacks on the Ping model that would create the actual instances of an outbound message for delivery (we called these Events), and then the dispatchers would need to block those callbacks in certain situations to cause a reschedule. It worked, I don’t want to get into the details of it, but it had one particular problem:

Events are an instance of a Ping associated with a Target for delivery. The one dispatcher we were running would do it’s selection of events to deliver based on target-types. Once we created the new Twitter target type and added a new dispatcher that only handled that one target type (this was all in our dev environment), the daemon would conflict with the other dispatcher. Which ever daemon picked up a ping first for it’s target type and then marked the ping as done was basically preventing the other daemon for processing the ping for its other targets.

The solution was to implement a new daemon, that we called Scheduler, and to move all the rescheduling code into this one serial process. Once we stripped all that out of the Ping model and the dispatcher code, we had a much leaner and faster system. We can now run as many dispatchers as our memory allows and configure them to handle various target types.

Using PingMe With Twitter

Posted: Jan 07, 2008 by Billy Gray Tagged pingme, rails

We’re big Twitter fans, and for quite some time we’ve wanted to allow PingMe users to interact with our service through Twitter. A number of folks have asked for it and, selfishly, we also wanted this capability for ourselves. Now, if you’re a twittaholic, you can access all mobile PingMe functionality straight through the service you know and love.

On a side note, this feature also introduces an alternate way to use SMS messages with PingMe. Previously, in order to send and receive SMS messages with our users (in a cost-efficient way) PingMe would send reminders through a provider’s sms-to-email gateways. These gateway’s are provided by most (but unfortunately not all) cell carriers, and some people pay an extra fee for the capability. Now that we’ve added support Twitter, you can use their service as a universal transport for SMS or even Instant Messaging.

In this post I’ll step you through the process of using PingMe with Twitter. Various details about how messages to create and update pings in this way are covered in older articles and our help section, so I’m going to stick to just the bits pertinent to Twitter.

To get started I’ll assume you already have a Twitter account, and are logged in to their web site. To be able to send get messages from PingMe on twitter, you have to “follow” the PingMe twitter account, ‘gpm’, like so:

Now that you’ve got your twitter account set up, log in to PingMe and click that “Add target” link under the Targets listing on the right side of the page. There’s not much to do but select ‘Twitter’ from the type drop-down and then enter your username on twitter:

Note that if you skipped the first step, where you follow gpm on Twitter, you’ll get an error in that last step.

Now that you’ve got a Twitter target for your account, you can have your pings sent there just like any other target:

So let’s try creating a ping from Twitter. We’ll use the web interface for our example, but keep in mind that you can do this in all the ways you interact with Twitter – including from your phone or IM. What we are doing is sending a direct message to gpm (‘d gpm …’) that contains a create-ping instruction.

The syntax is very similar to the format we use for creating remote pings from e-mail and SMS. The ‘5h’ tells ping me “five hours”, the “p:10” tells us to pester you every ten minutes until you respond with ‘done’, and the ‘t:t’ tells us that you want this ping sent to your Twitter targets (click here for info on setting default targets). The only new trick here is the addition of the ‘+’ sign. Since Twitter is conversational, we have to have a way of distinguishing your create messages from your updates, so after the direct message bit, you begin your ping creation with a plus sign.

Updates, as you might have expected, are simpler. The only caveat is that we don’t necessarily know which ping you are trying to update, so we assume it is the most recent one sent to you. You can send an update like this:

That message will update the most recent ping sent to you to be sent again in 30 minutes.