perlmojoliciousmorbo

Problem with Mojo::IOLoop timer before redirect


i have a sub in my Mojolicious Controller which is called when a csv file is uploaded through a http post. After the file is uploaded, a message gets rendered that say "you will be redirected in x seconds". so i want to implement Mojo::IOLoop::Delay and as callback i use the redirect statement. But i get the following error by Morbo:

Mojo::Reactor::EV: Timer failed: Transaction already destroyed at /usr/local/share/perl/5.22.1/Mojolicious/Plugin/DefaultHelpers.pm line 168.

controller code:

sub upload {
    my $self = shift;
      # Check file size
      return $self->render(text => 'File is too big.', status => 200)
      if $self->req->is_limit_exceeded;

  # Process uploaded file
  return $self->redirect_to('/') unless my $newCsv = $self->param('fileToUpload');
  my $size = $newCsv->size;
  my $name = $newCsv->filename;
  my $delay = 2;
  $self->render(text => "Thanks for uploading $size byte file $name.<br>
    You will be redirected in $delay seconds");
  Mojo::IOLoop->timer($delay => sub {
    $self->redirect_to('/');
    });
}

relevant routes:

$r->get('/')->to(controller => 'main', action => 'index');
$r->post('/uploadCsv')->to(controller => 'main', action => 'upload')->name('uploadCsv');

Thank you in advance


Solution

  • upload returns after Mojo::IOLoop->timer and nothing waits for the timer. You can try using Mojo::IOLoop->delay and $delay->wait instead. But I am not sure how it works. So it might be equivalent to just sleep.

    Do you really need to redirect from perl code? You can render some js with setTimeout for the same effect.

    In fact I would recommend moving all text and redirecting to js and render only json with some status information inside upload. So you can implement better UI with error handling.