tags:

views:

47

answers:

3

I have a (php/mysql) system that rewards users for doing things on the site. For the sake of the question, let's say a user gets a rose for every 5 comments they make.

The front page has a counter that shows how many roses have been earned today, and how many roses have been earned all-time. The rough logic is below:

//Save a single, discrete event. $user --> numerical value, 1:1.
function first($user) {
  //save values related to $user into TABLE_1;
  return second($user);
}

//Calculate the sum() of all numerical events for $user for today and save that.
function second($user) {
  //save values calculated from TABLE_1 into TABLE_2;
  return third();
}

//Calculate the sum() of all numerical events for all users 
function third() {
  //save values calculated from TABLE_2 into TABLE_3;
  return true/false;
}

When a comment is saved, the first() function is kicked off. first() saves a record of the comment event as a row in TABLE_1: user id, numerical value of the event (1, since 1 comment was saved), and timestamp.

Next, second() is called; second() does some math to figure out if the user has earned a rose with this comment and saves 3 values in TABLE_2: uid, roses_today, timestamp.

This is the value that's getting screwed up. For some reason, the value of roses_today varies from what it should be, sometimes being higher and sometimes being lower. There is no pattern -- some values are wildly high, some are barely too low, some are right on; there's no rhyme or reason here.

Also throwing a wrench in the works: if I call second($user) manually, the values it calculates and stores in TABLE_2 are correct. This function seems to only fail if it's being called in real-time.

Edit: Those suggesting it's a problem with the code that isn't there or that I should step through the code, please read the previous paragraph. This function seems to only fail if it's being called in real-time. Calling the very same function manually produces correct results.

+2  A: 

This is basically a "there's something wrong with the code I didn't show you" problem.
Therefore the best answer I can provide is: install a debugger like xdebug and e.g. netbeans as frontend and step through the code.

VolkerK
if I call second($user) manually, the values it calculates and stores in TABLE_2 are correct. This function seems to only fail if it's being called in real-time.
Entendu
Ok, and that's what a debugger is for (among other things). Set a breakpoint, run the script "in real-time", then step through the code from the breakpoint on, really easy. It _might_ be a timing problem, in which case the debugger could affect the outcome. But given the information from the question it's either the crystal ball or the debugger (or more information or coming up with a brilliant unit test ;-))
VolkerK
+1  A: 

Ok, your code is NOT wrong, according to you. Your server is smart enough to figure out where to fail to drive you nuts. You can, at least, do something like:

//Save a single, discrete event. $user --> numerical value, 1:1.
function first($_original_user_value) {
  echo 'first::' . $_original_user_value;
  $user = $_original_user_value;

  //save values related to $user into TABLE_1;

  if ($user !== $_original_user_value) {
    echo 'ERROR:: Something modified the value of $user';
  }
  return second($_original_user_value);
}

//Calculate the sum() of all numerical events for $user for today and save that.
function second($user) {
  echo 'second::' . $user;
  //save values calculated from TABLE_1 into TABLE_2;
  return third();
}

If the values at screen are not the same for both calls, you are having some kind of trouble. If you are running SQL queries, try saving/storing/displaying the error messages as well.

If your 'real-time' code is HTML and you don't want visitors to see these ugly echoes, try adding HTML comments to them.

Ast Derek
+1  A: 

The fact that your system works fine when you run things manually, but not on a live production system just screams race condition or configuration difference to me. Exactly how are you doing your math in second(). Do you do a query that does some SUM()/COUNT() aggregate functions on table_1, and then inserts the results into table_2? Do you do "SELECT * ..." and do all the math in PHP?

If you're running multiple queries, and they're NOT done within a transaction with appropriate locks on rows/tables, then you can be retrieving stale and/or bad data and basing your math on bogus values. If you're dealing with multiple "roses earned today" records in TABLE_2, and doing some kind of GROUP aggregating on those records in a "math" query, there's no guarantee the right version of "roses_today" will get used.

You've provided insufficient detail of your database schemas, queries, and "math" calculations to tell you what's wrong. Race conditions are hard enough to debug with full details. Forget trying to do it from inside an unlit utility closet on a moonless midnight.

Marc B
I love "math" in quotes, made me chuckle.The data that's inserted by second() is retrieved by a sum() query, then a tiny bit of math is done on the result (dividing the number), then THAT result is inserted. I do have a feeling that the sum() query is where things are going awry.
Entendu