Welcome Guest, Not a member yet? Register   Sign In
Controller "hanging"
#1

[eluser]Dunmail[/eluser]
I've a simple application written using Codeigniter and Datamapper which is used to record details of races. All well and good until the point at which the runners are logged crossing the finish line.

The controller reads the next finisher's position out of a session variable and passes it to the view which is simply a form with a button. When the button is pressed, the runner's time is calculated (the race start time is also in a session variable) and the details stored in to the underlying database (MySQL). The user is then immediately redirected back to the view/form ready for the next runner.

The controller extends the default CI_Controller class.

Here's the controller method to display the form:
Code:
public function finish(){
        $this->load->helper('url');
        $this->load->helper('form');

        $race = new Race_model();

        $data['title'] = $this->session->userdata('race_name');
        $data['start'] = $this->session->userdata('race_start');
        $data['finishers'] = $this->session->userdata('race_position');
        $data['count'] = $this->session->userdata('runner_count');
        $data['subject'] = 'finish';

        $this->load->view('templates/header', $data);
        $this->load->view('templates/menu', $data);
        $this->load->view('races-finish.php', $data);
        $this->load->view('templates/footer', $data);
    }

And here's the form handler:

Code:
public function store_finish(){
        $this->load->helper('url');
        $dest = base_url('races/finish');

        $result = new Result_model();

        $race_pos = $this->session->userdata('race_position');
        $data['race_id'] = $this->session->userdata('race_id');
        $data['race_position'] = $race_pos;
        $data['finish_time'] = time() - $this->session->userdata('race_start');

        $result->add_result($data);

        $this->session->set_userdata('race_position', ($race_pos + 1));

        // Move the user back ready for the next finisher.
        redirect($dest);
   }

The add_result method is:
Code:
public function add_result($data){
        $result = new Result();

        $result->race_id = $data['race_id'];
        $result->race_position = $data['race_position'];
        $result->finish_time = $data['finish_time'];

        return $result->save();
    }

The person who is using the system has reported that at some point, usually after around 50 - 60 runners being logged, the screen hangs and becomes unresponsive.

Other than those variables that I've needed to change to match my system (database name, password, etc) all config variables are the default values.

Any clues as to what I should be looking at in order to fix this? I'll try and get some logs later today after I get back from work to see if they show anything.
#2

[eluser]Tim Brownlaw[/eluser]
Hi,

Just a guess but Is your session timing out?


Cheers
Tim
#3

[eluser]Dunmail[/eluser]
Not sure. I've not seen the problem on my system though I haven't run large numbers of runners through it. There is a timeout if there's no activity (2 hours from memory) but every time there's a page transition it's reset.

However there may be other session settings that aren't being reset.
#4

[eluser]jonez[/eluser]
Gotta love user reports, "hangs and becomes unresponsive"...

Two things I'd check. If the browser is actually hanging, ie locks and user has to force quit, it's usually one of three things. A JS error/infinite loop, or an AJAX call that's set to run synchronously and taking forever to complete.

If you aren't using JS or AJAX, and the form submission is hanging, ie taking forever to complete, then it's probably database calls. I don't use ORM's for this exact reason, debugging performance issues is a nightmare. My suggestion would be to go through the code and look for any ORM call that's aggregating data during that post. It could be a bad relationship, or a bad query, or just the ORM doing something stupid. The PHP you posted is pretty simple so it's probably a long running query inside the ORM.

Do any of your ORM calls pull data for every active runner? I can see how that would start to tank after a large number of users if the query isn't optimized, which I doubt it is if it's from an ORM.
#5

[eluser]Dunmail[/eluser]
No JS or AJAX in this part of the application, in fact I added the option to suspend AJAX when adding runner details as it was slowing the user's (rather old) machine down.

The post is a simple insert in to a single table, no relationships involved. (As an aside, I've no many-to-many relationships, they are all one-to-many).

I *think* the user has already entered all runner data and is now simply trying to "run" a test race, quite possibly after restarting the machine after a day or two away. There's no pulling of data from the database during this phase of operation, the details are loaded in to session variables and then used continually, updating the current runner number as it goes.

I don't know exactly "how" the application hangs, whether it's just this part of the app and other parts, non-database related, continue to work or whether the whole session is stuffed. As I said in the OP, I'm going to spend a couple of hours tonight running a lot of data through this to see if I can reproduce it.
#6

[eluser]Tim Brownlaw[/eluser]
If you can run the profiler on it - that may shed some light on what's going on!
#7

[eluser]CroNiX[/eluser]
Since you are using an ORM, the profiler won't show you anything db related since you're not using the native CI database methods which is most likely where the problem is, although it still might be helpful. I'd advise getting the RAW sql queries that the ORM is generating and run them as a straight sql query with an EXPLAIN directly within mysql, or another app like phpmyadmin, navicat or others. It would probably also be worthwhile to turn on slow query logging in mysql and run your app for awhile and then check the slow query log.

I'd think your ORM is pulling in way too much unnecessary data, which is typical of ORMs, or your tables aren't properly indexed on the fields you are searching on, or both.

Your code also never checks to see if the session returns actual data before performing tasks. Requested session data that does not exist will return boolean FALSE.

If you are using cookies to store your session data, you might also want to check how much data you are storing. If it's more than 2kb (encrypted), it will break the session as the encrypted data will be stored incomplete which means there is no way to decrypt it. This is a cookie limitation. Database sessions do not have this limitation, and is also more secure since the session data is not stored clientside in a cookie (only the encrypted session ID).
#8

[eluser]Dunmail[/eluser]
Grr!

It turned out to be user error.

The button in the view is disabled when all runners have been logged as having finished. The user had requested that a block of text: "x out of y runners have finished" be removed so there was no other clue. They mistook the disabled button for hanging/lockup. I think I'll update the button text to so it's more obvious.

Thanks to all for your suggestions, I'll update the various bits of code to make things more robust.
#9

[eluser]InsiteFX[/eluser]
try changing this:
Code:
redirect($dest);

// to
redirect($dest, 'refresh');
#10

[eluser]Dunmail[/eluser]
The redirect wasn't anything to do with the problem.

There was a missing piece to the puzzle that the user hadn't told me. After starting the race the user continued to add runners. However, this variable:

Code:
$this->session->userdata('runner_count');

Was only ever set when the race was started, i.e. it registered the number of runners at that point in time, so any runners entered after that point weren't taken in to consideration when the code disabled the button after "runner_count" finishers had crossed the line. The user then saw this as locking up.

I set the runner count at the start of the race partly because I assumed that all runners would have been entered on the system by that time and partly because I didn't want to have to continually get the count and update it.




Theme © iAndrew 2016 - Forum software by © MyBB