According to Wikipedia, a Heisenbug is a whimsical computer programming jargon term for a software bug that seems to disappear when one attempts to study it.
That’s the perfect term to describe a bug I recently fixed in our application code. Let me describe to you the symptoms first:
On a mobile phone, the user completes a repeating task. Usually, the server gives back a new date 7 days from now. Every once in a while, though, the server would give back a new date 8 days in the future.
I was able to reproduce it fairly easily. So far, so good. However, when I switched the device to our development server, where I could look at the logs, the problem never happened. Similarly, when I logged in via the web interface, the problem never happened. I even tried to log in to the production server’s console and recreate the error, with no luck. Only with our mobile clients and the production server did this error would occur.
I thought it was an error in our repeating code logic, so I stared at that code for a while. Finally, I added a bunch of logging, and at the end, wrote…
if task.title = "bdafh" email(repeat_log, :to => "tim@*****.com") end
… which emails the log of what happened to me if the task’s title is named “bdafh”. After a couple tries, I reproduced the problem, and received a tell-tale email message. The only difference between the successful repetition (7 days) and the unsuccessful repetition (8 days) was today’s date. In other words, sometimes the server thought that it was tomorrow!
From there, I knew that the problem was a time zone issue. In every web request, we had the following code:
before_filter :set_time_zone def set_time_zone if user_signed_in? and current_user.time_zone Time.zone = current_user.time_zone end end
Mobile users, however, aren’t technically “signed in” through our authentication system, and instead have an API key. Therefore, Time.zone wasn’t getting set for those users, and instead, they inherit whatever time zone was used by the last user that did have a time zone setting.