Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Dancer & Plackup - Redirect not refreshing page data

by jeromek (Novice)
on Aug 07, 2014 at 12:02 UTC ( [id://1096607]=perlquestion: print w/replies, xml ) Need Help??

jeromek has asked for the wisdom of the Perl Monks concerning the following question:

Hi All Monks,

First of, let me say I haven't used perl for web dev in a long time and was still stuck on cgi. When asked to do small dev with the technology of my choice, I jumped on the occasion and ended up using Dancer. What a refreshing way to write web apps, easy to install, develop with, deploy...

Now that my small app is finished, I deploy it in production with plackup and starman behing nginx.

sudo -u nginx /usr/local/bin/plackup -E production -s Starman --workers=2 -l /tmp/plack.sock -a bin/app.pl

I have some standard crud stuff and in particular a get and edit.
A route get /get/:id that renders the page with data and a submit edit button
A route post /edit/:id that updates the database and ends with a redirect "/get/$id"

This worked great in dev mode, running perl bin/app.pl but after deploying in prod through plackup, the redirect after edit shows the get page but the data on the page is not updated. Refreshing the page (F5) does show the updated data.

Dancer is great but unfortunately lacks a bit of detailed doc and community. Hence I come here to ask for your wisdom.
Is there some caching issue ? Is there a way/option to redirect and refresh data ?

Thanks for your input.

Replies are listed 'Best First'.
Re: Dancer & Plackup - Redirect not refreshing page data
by choroba (Cardinal) on Aug 07, 2014 at 13:00 UTC
    I'm not sure, but try to turn off caching in your production config:
    # cache route resolution for maximum performance route_cache: 0
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      I thought about that but it looked like just route path caching to avoid searching the whole registry, not actual data.
      Anyways, tried it, no luck

        I think I've tracked it down to starman.
        With only 1 worker, all works fine. I guess the second worker picks up the other request but not in the same DB transaction and doesn't see the update.

        The question is now is it an internal starman cachine problem or am I doing something wrong with my database connection ?
        My guess is that it's not only database because the session info is not pickup by the 2nd worker either so starman is doing something wrong, workers are not synchronized.

        Is there any Starman-specific community I could ask ?

Re: Dancer & Plackup - Redirect not refreshing page data
by Anonymous Monk on Aug 07, 2014 at 20:48 UTC

    Is there some caching issue ?

    Probably in your code :) if you can post a small program that reproduces the problem, we can figure it out

    Dancer is great but unfortunately lacks a bit of detailed doc and community.

    You know, whenever I hear someone complain about lack of support and documentation, I am always very surprised, because to me it always seems there is a sea of documentation and support -- can you be more specific?

      Here is the test case: Controller:
      package Test::TestController; use Dancer ':syntax'; use strict; use Test::Model::Test; our $VERSION = '0.1'; prefix '/test'; route(); sub route { hook 'before' => sub { if (! session('user') && request->path_info =~ /^\/test\// && +request->path_info !~ m{^/login}) { var requested_path => request->path_info; request->path_info('/test/login'); } }; get '/login' => sub { template 'login_test.tt', { }; }; ##log user in. Validate authentication then redirect to user base +route post '/login' => sub { session user => {id => 1, role =>{ id => 1} }; redirect '/test/website/get/1'; }; get '/website/get/:id' => sub { ##check we're not being passed non id stuff unless (params->{id} =~ /^[\d]+$/) { redirect '/test/login'; r +eturn } my $website = Test::Model::Test::get_website(params->{id}); + ##only for admin for all websites ##check that the website is owned by this user otherwise unless (session('user')->{role}->{id} eq Test::Model::Test::RO +LE_ADMIN || $website->{created_by} eq session('user')->{id}) { redirect '/login'; } template 'website_test.tt', { 'values' => $website, 'form_url' => '/test/website/edit/'.params->{id}, }; }; post '/website/edit/:id' => sub { ##check we're not being passed non id stuff unless (params->{id} =~ /^[\d]+$/) { redirect '/test/login'; r +eturn } my $website = Test::Model::Test::get_website(params->{id}); + ##only for admin for all websites ##check that the website is owned by this user otherwise unless (session('user')->{role}->{id} eq Test::Model::Test::RO +LE_ADMIN || $website->{created_by} eq session('user')->{id}) { redirect '/login'; } my $param_ref = params; Test::Model::Test::edit_website(session('user'), $param_ref); ##Redirect to add a new website with a flash message #flash message => 'Website successfully edited!'; redirect '/test/website/get/'.params->{id}; }; } true;
      Model
      package Test::Model::Test; use Dancer::Plugin::Database; use Dancer::Logger; use constant ROLE_ADMIN => 1; ##Edits a new website sub edit_website($$) { my ($user, $website) = @_; database->quick_update('test_website', {id => $website->{id}}, { name => $website +->{name}, url => $website- +>{url}, }); database->commit(); } ##Return sthe website object . sub get_website($) { my ($id) = @_; my $website = database->quick_select('test_website', { id => $id } +); return $website; } true;
      Template
      <form action="<% form_url %>" method="post" id="f-submit-form" enctype +="multipart/form-data"> <fieldset> <h2>Edit Website</h2> <ul> <li id="f-container-website-name"> <label for="f-website-name">Name</label> <input type="text" name="name" id="f-website-name" <%IF va +lues.name %>value="<% values.name %>"<% END %> /> </li> <li id="f-container-website-url"> <label for="f-website-url">Url</label> <input type="text" name="url" id="f-website-url" <%IF valu +es.url %>value="<% values.url %>"<% END %> /> </li> <li id="f-container-submit"> <button value="Submit" class="maia-button" id="sub +mit" type="submit">Submit</button> </li> </ul> </form>
      Login template
      <div class="login-container"> <div class="login-header"> Login </div> <% IF err %> <div class="login-error-container-enabled">Incorrect username +/ password</div> <% END %> <div class="login-form-container"> <form id="f-form-login" action="<% request.uri_base %>/test/lo +gin" method="post" enctype="multipart/form-data"> <fieldset> <ul> <li id="f-container-username"> <label for="f-username">Username</label> <input type="text" name="username" id="f-usern +ame"/> </li> <li id="f-container-password"> <label for="f-password">Password</label> <input type="password" name="password" id="f-p +assword"/> </li> <li id="f-container-submit"> <button value="Submit" class="button" id="subm +it" type="submit">LOGIN</button> </li> </ul> </fieldset> </form> </div> </div>
      DB
      create table if not exists `testdb`.test_website ( id integer primary key auto_increment, name varchar(255) not null, url varchar(255) not null ) ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO `testdb`.test_website(name, url) values ('test1', 'mytest. +com');

      Steps:

      • Login (any user/pwd will do for the test)
      • In /website/get/1 , change the name
      • Click Submit
      • See the name is not refreshed
      • F5, name is refreshed

      Above steps work fine when running perl bin/app.pl
      Test fails when running
      sudo -u nginx /usr/local/bin/plackup -E production -s Starman --workers=2 -l /tmp/plack.sock -a bin/app.pl &

      Hopefully somebody can point to what I'm doing wrong in my code. Thanks for taking the time.

        Can you also show config.yml and production.yml?
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      Done some more tests and it might be nginx causing problems after all. sudo -u nginx /usr/local/bin/plackup -E production -s Starman --workers=2 --port 3000 --preload-app -a bin/app.pl Having starman listen on port 3000, accessing it directly without going through nginx works fine.

        So does your nginx config have "cache" anywhere?

        You might add in your dancer app  header('Cache-Control' =>  'no-store, no-cache, must-revalidate');

      Forgot to add that starting starman with only 1 worker "fixes" the problem which makes me think some context is not shared between the workers.

        Try  return redirect... instead of a bare redirect

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1096607]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-03-28 23:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found