Tempo update: date range adjustments

2009-01-25 19:00:00 -0500


We made a couple of small but necessary adjustments to Tempo’s user interface this evening. The date range selector at the top of the screen had been causing some confusion and from there some unexpected exceptional situations [also known as “bugs”]. As you can see here, there’s a date range selector, and a pair for date fields that allow you to select your own date range manually:

Previously, if you typed dates into those boxes or used the calendar pop-up to change their values, the date range would become immediately unselected. This is because the date range took precedence over what was present in the start_date and end_date fields. If you selected a new date range, the start_date and end_date fields would not change until you clicked “Run Report”, and then you’d see that the range took precedence in the report, and their values would be updated to match the range.

That’s a little bit confusing! Some users thought this was a bug and so would clear out the start_date and end_date fields, and then set a range, hit “Run Report”, and nothing would happen because the server wouldn’t process the report without the missing values – even though they would be ignored. Bug on my part.

So, not only has that been fixed, but the start and end date fields are now updated instantly to the correct dates when you select one of the ranges, so that you get the appropriate visual feedback and can see what it is you’re asking for when you run the report. Apologies for the confusion!

As always, if you see anything weird, please send us a message at support@zetetic.net.


The Dark Side

2009-01-21 19:00:00 -0500


Sometimes you come across a webpage that is just so bizarre and absurb, you just don’t know how to introduce it to other people. But you still do it anyway. (h/t to Chip Z)

It only gets better from there (safe for work).

In other news we’re still hammering away at STRIP for the iPhone. We take breaks for food and small diversions, but we’re still plugging away.

Update: it would appear that not long after we posted this, the website in question took the page down.


My Spooky Friends Net

2009-01-20 19:00:00 -0500


Warren Ellis writes:

So, are people rolling their own private microblogging networks yet? And knocking together mobile pages and writing/hacking desktop apps to work with their private microblogging networks yet? It would seem to me to be the obvious outgrowth of the Twitter phenomenon: ambient communication for secret societies.

(Which you can take to mean “gated communities,” “dev teams” “people who like their privacy” or “bomb-throwing anarchists.”) …

I’d happily run two microblogging desktop apps: one for Twitter, and one for My Spooky Friends Net. And, after a while, I’d probably stop using the Twitter app, I’d imagine.

I’d be willing to work on My Spooky Friends Net.

Update: There are a ton of apps that work with Laconica / identi.ca already!


Deep Thought

2009-01-20 19:00:00 -0500


I need an HTCPCP daemon.

Or an intern.

There is coffee all over the world. Increasingly, in a world in which computing is ubiquitous, the computists want to make coffee. Coffee brewing is an art, but the distributed intelligence of the web-connected world transcends art…

I’m gonna go make some coffee. Blog post on really simple ruby daemonizing coming soon. Stay tuned.


Dead Simple Ruby Daemons Using Looper

2009-01-20 19:00:00 -0500


There seems to be a bit of interest in the Ruby community lately in putting together handy libraries for creating Ruby daemons, so I thought I’d throw our own particular solution into the mix. Our solution intentionally avoids a lot of the common daemonizing tasks (like detaching from the terminal) so it might not be quite appropriate to call it daemonizing, but it fills our requirements nicely. (As an aside, check out Kenneth Kalmer’s new library daemon-kit for a nice actual-daemon implementation in Ruby.)

We originally tried coding things by hand using Daemons, and then modularizing our oft-repeated code to stay DRY, but we kept running into stability issues. Also, when you fork a Ruby daemon, particularly one that’s loaded up a large stack in memory, you end up at least briefly using twice as much memory. So, memory hogging and crashing needed to be avoided.

None of our daemons required advanced process handling, either. They were simple, single instance workers that had very particular tasks (like schedulers and message handlers for PingMe). We found ourselves asking, “do we really need to be forking child processes for this?”

The answer is no. Instead we are using a module we just pushed to Github that we call Looper. It allows us to take any bit of code or a class and run it as a kind of daemon. Or, more specifically, the class uses Looper to take advantage of its simple signal trapping, loop handling (including sleeping), and the class can rely on Looper to catch any unhandled exception, report it, and keep on keepin’ on.

The loopme method takes a block that it runs for you, handles sleeping between runs, and will catch any unhandled exceptions that bubble up. Thus, if you want to exit on a particular exception, you’ve got to rescue it in your code and set @run to false. It also sets up signal trapping so that signals TERM, INT and HUP will all cause the loop to end (I’d be open to changing this behavior or adding additional signal responses if anybody has an interest).

Here’s an example “daemon” that uses looper to kick it:



require 'looper'
require 'twitter'

class DoSomething
include Looper

def initialize(config)
@run = true
# do config stuff, etc...
@sleep = config[:sleep].nil? ? 60 : config[:sleep]
end # initialize

def run
loopme(@sleep) do
begin
# this is where the meat of your code goes...
messages = twitter.direct_messages({:since => Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z")})
rescue Twitter::EpicFailure => e
puts "bailing out, dude!"
# set run to false to put the kabosh on the next run
@run = false
end
end
end
end

# and here's how we kick it off:
DoSomething.new( { :sleep => 10 } ).run

Pretty simple, right? No coding up the signals, the sleeping, the global exception handler, etc. You can take a look at looper.rb to see exactly what it does for you. From here, starting and stopping our script is really easy, and can be re-used for each of our daemons. It boils down to starting it up with nohup (and script/runner because we like having our rails stack), and then killing it later with the PID:

$ nohup script/runner -e RAILS_ENV /path/to/DoSomething.rb

There’s no need to use Rails’ script/runner, you could just call ruby itself and save yourself a lot of memory ;-)

The following is an init script that we use to start and stop any of our Looper daemons:



#!/bin/bash
#
# chkconfig: 345 70 30
# description: control script for daemons
#

usage(){
echo $"Usage: $0 {start|stop|restart} {daemon1|godzilla|voltron}"
}

# daemon name is required as second param
if [ "$2" = "" ]
then
usage
exit 5
fi

# RAILS_ENV?
if [ "$RAILS_ENV" = "" ]; then
RAILS_ENV='development'
fi

# RAILS_DIR?
if [ "$RAILS_ENV" = "production" ]; then
RAILS_DIR='/www/app/current'
else # assume development
RAILS_DIR='/www/dev.app/current'
fi

PROGRAM="${RAILS_DIR}/daemons/${2}/looper.rb"
RUNNER="${RAILS_DIR}/script/runner"

LOG="/var/log/app/daemon_${RAILS_ENV}.log"

# if the daemon is missing, well, the daemon is missing!
test -f $PROGRAM || exit 5

# See how we were called
case "$1" in
start)
nohup $RUNNER -e $RAILS_ENV $PROGRAM >> $LOG 2>&1 &
;;
stop)
PID=`ps auxw | grep ${PROGRAM} | grep -v grep | awk '{ print $2 }'`
echo "Stopping PID: ${PID}"
kill $PID
sleep 2
;;
restart)
$0 stop
$0 start
;;
*)
usage
exit 1
;;
esac

exit 0
Zetetic is the creator of the super-flexible Tempo Time Tracking system.