in reply to Getting query string with CGI::Fast

Am I doing things correctly?

Not entirely, I suspect. You have 2 different CGI objects: 1 in test.cgi and 1 in Myapp. That seems inherently incorrect. Take the object you already have in test.cgi and pass it to the Myapp subs if that's what you want. Alternatively you could have Myapp subclass CGI::Fast and then just use that in test.cgi and call methods on that object from there. Or if you don't want to subclass CGI::Fast you could have a separate object of Myapp on which to call methods. TIMTOWTDI.

Here's a simplified example using that last of these approaches:

#!/usr/bin/perl -T package Myapp; use strict; use warnings; use Try::Tiny; sub new { my ($class, $q) = @_; return bless {q => $q}, $class; } sub appy { my $self = shift; my $action = $self->{q}->param('action') || 'bailout'; try { $self->$action; } catch { print "Unrecognized action : $action\n"; } } sub do_something { print "do something called\n"; } package main; use strict; use warnings; use CGI::Fast; use Try::Tiny; my $n = 0; while (my $q = CGI::Fast->new) { my $query = $q->param('node'); print "Content-type: text/plain\n\n"; ++$n; print "You are request number $n. Have a good day!\n"; print "query: $query\n"; my $app = Myapp->new ($q); try { $app->$query } catch { error() }; print "done!\n"; } sub error { print "An error occurred.\n"; }

Note that I've combined the module and script into one file for ease of this illustration (it's an SSCCE, albeit you need an FCGI-capable webserver to test it). If you want to split them out again, just add use Myapp; back into the script. I've added Try::Tiny to catch the missing methods rather than bother with dispatch tables just to show another way of doing this but there's nothing wrong with dispatch tables if you prefer them. Equally you could just use UNIVERSAL::can to test the method's existence - so many options! I've used strict and warnings everywhere and so should you.

To answer the other avenue of discussion, the while loop is absolutely necessary otherwise you will not have the persistence (ie. $n will never increase). Have a think for yourself about why this is.


🦛

Replies are listed 'Best First'.
Re^2: Getting query string with CGI::Fast
by Anonymous Monk on Jul 28, 2020 at 09:51 UTC

    Thank you so much for your explanation on the "while" vs "if" condition and for your beautiful code - as someone who writes procedural code, I never quite get round to switching to object-oriented. Will try to learn (and adapt) from yours.

    I have a question about persistence. Suppose the module Myapp uses other modules, are these other modules also stored in memory so they are not loaded for every request?

      Suppose the module Myapp uses other modules, are these other modules also stored in memory so they are not loaded for every request?

      Short answer: yes.

      Any module which a script uses is loaded into memory at compile time, including all the modules used by those modules and so on. This memory stays used until the script exits. For long-running scripts such as those under FCGI this means that all those modules remain in memory for a long time. Each web request to your FCGI script will either encounter an existing FCGI process where all those modules are ready and therefore have no startup penalty or occasionally will have to spin up a fresh FCGI process which will take longer because it loads all the modules.

      You can manage this somewhat by loading modules on demand at run-time instead of at compile time. Suppose there's a task your script will need to perform only once in every 10,000 runs and which needs a heavy module. You would not necessarily want that module taking up lots of RAM unnecessarily for 9,999 runs when it isn't needed. This sort of memory and process management is something you will probably want to consider if you are going to use FCGI (or any other persistent back-end) for serious purposes.


      🦛

        I'm using shared hosting. Being new to FCGI, I have absolutely no idea how things would turn out when and if I put the code to use. For the time being, I have the non-FCGI version but have known for a long time FCGI would make things faster. Does the persistence automatically go away after some time of inactivity? Like no request for a certain number of minutes?