Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Change cgi script to PSGI app

by mohan2monks (Beadle)
on Sep 11, 2014 at 07:28 UTC ( [id://1100260]=perlquestion: print w/replies, xml ) Need Help??

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

Hi I am mostly used to writing CGI style scipts and trying to move a existing CGI script to a PSGI app and deploy it.

The website is running on APACHE and written in PHP.
As this will be the only perl script i can't deploy on mod_perl.
As APACHE already loads php5 module loading perl also in every apache child only for a script will be a waste.

I have been reading about PSGI Plack and converted my script to a PSGI complaint app and tested it.

#mycgiapp.psgi #!/usr/bin/perl use strict; use Plack::Request; use forks::BerkeleyDB; use XML::Simple; use JSON qw(encode_json); use MIME::Base64 qw(encode_base64); use DBI; use SOAP::Lite(); use POSIX qw(ceil); use Data::Dumper; $XML::Simple::PREFERRED_PARSER='XML::Parser'; $SOAP::Constants::DO_NOT_USE_CHARSET = 1; my $app = sub { my $env = shift; my $req = Plack::Request->new($env); my $input=$req->parameters(); my($out)=GetOutput($input); if ($input->{'format'} eq 'json'){ my $json=JSON->new->utf8->encode($out); return [ 200, ['Content-Type' => 'application/json'], [ $json ], ]; } else{ my $xml=XMLout($out,RootName=>"Result",keepRoot=>0,NoAttr=>1, Ke +yAttr => []); return [ 200, ['Content-Type' => 'text/xml'], [ $xml ], ]; } }; sub GetOutput { #CGI script code # Runs multiple threads/forks to collect data from various apis with S +OAP calls return ($headers,$out); } #RAN IT WITH plackup C:\httpd\myapp>plackup -D -r --host 192.168.110.181 --port 5010 --app +myapp.psgi Watching ./lib myapp.psgi for file updates. HTTP::Server::PSGI: Accepting connections at http://192.168.110.181:50 +10/ 10.1.1.4 - - [11/Sep/2014:11:33:57 +0530] "GET /

I have noticed that the command prompt never returns and if i close it service stops.
How can start this from command line and keep it running after i close putty or command prompt.
I can run this service as standalone service as it is used by other scripts and not directly by end users.
What would be best approach i can follow to deploy on production.
It should be available as apache is for other php pages.
Can i run it from apache itself.
If as a standalone server what should i use from plack like starman etc
Please help. Update

I have set up ubic on my system to start and manage starman service as

use Ubic::Service::Starman; my $Config={ server_args => { 'listen' =>'10.1.1.5:8080', 'workers' =>16, 'backlog' =>1024, 'max-requests'=>1000, 'daemonize' =>'', 'user' =>'perl', 'access-log' =>'/var/log/psgi/access.log', 'error-log' =>'/var/log/psgi/error.log', 'app' =>'/var/www/myapp/myapp.psgi', }, app => "/var/www/myapp/myapp.psgi", status => sub {}, ubic_log=> '/var/log/psgi/ubic.log', stdout => '/var/log/psgi/stdout.log', stderr => '/var/log/psgi/stderr.log', user =>'perl', group =>'perl', cwd =>'/var/www/myapp', pidfile =>'/var/log/psgi/myapp.pid', }; return Ubic::Service::Starman->new($Config); # ubic status myapp # ubic myapp not running Can't locate /var/www/myapp/Config.pl in @INC (@INC contains: /usr/lo +cal/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl / +usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at / +var/www/myapp/myapp.psgi line 166.
While i get ubic status as not running the top command shows starman running and accepting connections.
But i get file not found in @INC error.
I have given cwd path and also changed the paths in my psgi app to absolute from relative earlier.
What am i doing wrong here?

UPDATE

I think this is more to do with ubic as it status is unkown or not running it never changed to working directory that was provided in config options
earlier using use Ubic::Service::Starman; i was getting ubic status as not runing.. and @INC
But now i changed it to below and ubic status is unknown.

use Ubic::Service::Plack; my $Config={ server => "Plack::Handler::Starman", server_args => { 'listen' =>'10.1.1.5:8080', 'workers' =>16, 'backlog' =>1024, 'max-requests'=>1000, 'daemonize' =>'', 'reload' =>'', 'user' =>'perl', 'access-log' =>'/var/log/psgi/access.log', 'error-log' =>'/var/log/psgi/error.log', 'app' =>'/var/www/myapp/myapp.psgi', }, app => '/var/www/myapp/myapp.psgi', status => sub {}, ubic_log=> '/var/log/psgi/ubic.log', stdout => '/var/log/psgi/stdout.log', stderr => '/var/log/psgi/stderr.log', user =>'perl', group =>'perl', cwd =>'/var/www/myapp/', pidfile =>'/var/log/psgi/domfares.pid', }; return Ubic::Service::Plack->new($Config);
starman service is running though ubic status is unknown
Now ubic watchdog tries to start this service every minutes thinking it dead and service restarts every minute.
Starman error log 2014/09/12-14:25:52 Worker processes cleaned up 2014/09/12-14:25:52 Server closing! Process Backgrounded 2014/09/12-14:26:53 Starman::Server (type Net::Server::PreFork) starti +ng! pid(20742) Binding to TCP port 8080 on host 10.1.1.5 with IPv4 2014/09/12-14:26:53 Can't connect to TCP port 8080 on 10.1.1.5 [Addres +s already in use] at line 68 in file /usr/local/share/perl5/Net/Server/Proto/TCP.pm 2014/09/12-14:26:53 Received QUIT. Running a graceful shutdown 2014/09/12-14:26:53 Worker processes cleaned up 2014/09/12-14:26:53 Server closing! ##Ubic log [Fri Sep 12 14:24:53 2014] 19878 guardian name: ubic-guardian st +arman --backlog 1024 --access-log /var/log/psgi/access.log --max-requ +ests 1000 --app /var/www/myapp/myapp.psgi --error-log /var/log/psgi/e +rror.log --workers 16 --reload --listen 10.1.1.5:8080 --user perl -- +server Plack::Handler::Starman --daemonize /var/www/myapp/myapp.psgi [Fri Sep 12 14:24:53 2014] 19878 obtaining lock... [Fri Sep 12 14:24:53 2014] 19878 got lock [Fri Sep 12 14:24:53 2014] 19878 guardian pid: 19878 [Fri Sep 12 14:24:53 2014] 19878 daemon pid: 19879 [Fri Sep 12 14:24:53 2014] 19878 child guid: 2916133834 [Fri Sep 12 14:25:52 2014] 19878 sending SIGTERM to 19879 [Fri Sep 12 14:25:52 2014] 19878 daemon 19879 exited [Fri Sep 12 14:25:52 2014] 20296 guardian name: ubic-guardian st +arman --backlog 1024 --access-log /var/log/psgi/access.log --max-requ +ests 1000 --app /var/www/myapp/myapp.psgi --error-log /var/log/psgi/e +rror.log --workers 16 --reload --listen 10.1.1.5:8080 --user perl -- +server Plack::Handler::Starman --daemonize /var/www/myapp/myapp.psgi [Fri Sep 12 14:25:52 2014] 20296 obtaining lock... [Fri Sep 12 14:25:52 2014] 20296 got lock [Fri Sep 12 14:25:52 2014] 20296 guardian pid: 20296 [Fri Sep 12 14:25:52 2014] 20296 daemon pid: 20297 [Fri Sep 12 14:25:52 2014] 20296 child guid: 2916139767 [Fri Sep 12 14:26:52 2014] 20296 sending SIGTERM to 20297 [Fri Sep 12 14:26:52 2014] 20296 daemon 20297 exited [Fri Sep 12 14:26:52 2014] 20738 guardian name: ubic-guardian st +arman --backlog 1024 --access-log /var/log/psgi/access.log --max-requ +ests 1000 --app /var/www/myapp/myapp.psgi --error-log /var/log/psgi/e +rror.log --workers 16 --reload --listen 10.1.1.5:8080 --user perl -- +server Plack::Handler::Starman --daemonize /var/www/myapp/myapp.psgi [Fri Sep 12 14:26:52 2014] 20738 obtaining lock... [Fri Sep 12 14:26:52 2014] 20738 got lock [Fri Sep 12 14:26:52 2014] 20738 guardian pid: 20738 [Fri Sep 12 14:26:52 2014] 20738 daemon pid: 20739 [Fri Sep 12 14:26:52 2014] 20738 child guid: 2916145800 [Fri Sep 12 14:26:55 2014] 20738 sending SIGTERM to 20739 [Fri Sep 12 14:26:55 2014] 20738 daemon 20739 exited
Why ubic status is unknown?

Replies are listed 'Best First'.
Re: Change cgi script to PSGI app
by tobyink (Canon) on Sep 11, 2014 at 09:00 UTC

    You have several deployment solutions, but they all boil down to an initial choice between two main options:

    1. You can serve the app through Apache, so it appears to be just one more "page" on your current web server; or

    2. You can serve the app through a stand-alone server, in which case it will be running on a different port (or even on a different host if you liked). Optionally, Apache can be configured to use mod_rewrite/mod_proxy to make the app appear like you've used choice #1 above.

    If you want to serve your app through Apache, mod_perl is usually a fairly simple way to set it up, and a reasonably efficient way to run it, but you've already ruled that out. You can accomplish something similar using FastCGI, though I've always found that trickier to set up.

    The final Apache-based way is to deploy a PSGI script as CGI. Just rename your .psgi file to .cgi, mark it as executable (chmod +x), and make sure it includes this shebang line:

    #!/usr/bin/env plackup

    Now it's just a regular CGI script, albeit one that uses Plack a lot internally. See Plack::Handler::CGI for details. This is a really easy deployment option, which works just about anywhere. However, because your whole PSGI app needs to be loaded for each request, it's not an especially efficient solution. (For simple apps that don't load a bajillion modules, it's often perfectly acceptable.)

    Using a stand-alone server though is generally the most popular option. There are various PSGI servers on CPAN, including Starman and HTTP::Server::PSGI (which comes bundled with Plack). They each have different performance profiles. Generally speaking, you trade CPU for memory. The faster ones take up more memory. The smaller ones are slower. Test out a few, and see which one performs best for your app.

    As you have noted, you'll want to run this as a background process, and probably do things like monitor it, to check that it doesn't crash (and automatically restart it if it does crash), and have it auto-restart after a hardware reboot, and so on.

    For this I strongly recommend using Ubic to create /etc/rcX.d/-style services. In particular, you'll want the Ubic::Service::Plack plugin (or if you deploy via Starman, Ubic::Service::Starman is another option).

    For my personal site, I use an interesting blend of Perl solutions. Most of the site are static HTML pages, generated from Atom by a Perl script, and served though Apache. The e-mail contact form is a PSGI app deployed via CGI. My SPARQL endpoint is another PSGI app running on a stand-alone HTTP::Server::PSGI server, using Ubic to keep it running, and with some custom Ubic plugins to monitor its memory usage, and restart it if the process gets too big. Over-engineering much?

    Anyway, I'll stop rambling, but I hope this has been of some help.

    TL;DR: use Ubic

      Yes it is been of much help.
      Thank you very much it should take me somewhere though i am still away from putting it to production.

      Toby, just keep writing more of those “ramblings” of yours, anytime!   But I do find myself with a couple of questions / points for clarification, if you would, please.

      Ordinarily, I do use PSGI, by means of Plack.   (N-O-T to ignite any religious wars here, I do not use mod_perl.)   If everything is going to be done on a single computer, I simply let Apache own the child processes, e.g. using mod_fastcgi.   My only use for plackup is as a command-line tool which allows me to run the scripts and connect to them on localhost for development purposes only; it is never put into any “shebang” lines.   Therefore, I am quite puzzled by your other suggested use for it.   I don’t quite understand you on that point ...

      Although I have never had need to use Plack’s adapter for CGI-scripts, its docs seem sensible.   Quite frankly, I just design apps to run under Plack.

        "Therefore, I am quite puzzled by your other suggested use for it. I don’t quite understand you on that point"

        The use of plackup in a shebang line for CGI scripts is documented in Plack::Handler::CGI. If you're interested in how/why it works, read on.

        plackup's normal behaviour is to run a server which listens on a TCP port, and handles multiple HTTP requests, and keeps going until it gets killed. You can observe this behaviour by running:

        plackup -e'sub { [200,[],[q/ok/]] }'

        It will print out a URL; you can paste that into your browser, and it will serve up a small text file containing the word "ok". And you can hit "reload" and it will do it again and again. Awesome. But, of course, not what you want from a CGI script! So how is plackup any good in a shebang line?

        Hit Ctrl+C to kill plackup, and then set the following environment variables:

        GATEWAY_INTERFACE=1 SERVER_NAME=localhost SERVER_PORT=8080 REQUEST_METHOD=GET SCRIPT_NAME=-e

        Now run this again:

        plackup -e'sub { [200,[],[q/ok/]] }'

        And you'll see that instead of spawning an HTTP server and printing out its address for you, plackup now behaves like a CGI script, printing out the response headers and body to STDOUT.

        plackup (or rather the guess sub defined in Plack::Loader) detects that it's running in a CGI environment and behaves appropriately.

Re: Change cgi script to PSGI app
by Corion (Patriarch) on Sep 12, 2014 at 07:27 UTC

    Regarding using Ubic for running your webserver: You don't show us what is in line 166 of myapp.psgi. My guess is that it is a line like require 'Config.pl';, which likely means that the "current directory" is not what your program thinks it should be.

    Ubic::Service::Starman (through inheritance from Ubic::Service::Plack) has a cwd option that maybe allows you to set up the correct directory for the program.

      Line 166 was

       require './Config.pl' i also tried require '/var/www/myapp/Config.pl'

      In my configuration for ubic service i have provided CWD path as /var/www/myapp
      but ubic service status says not running
      The same code runs fine if i use plackup without Starman as server.

      plackup -D -r --host 10.1.1.5 --port 8080 --user perl --access-log /va +r/log/psgi/access.log --max-requests 1000 --error-log /var/log/psgi/e +rror.log --app myapp.psgi
      I ran this command from /var/www/myapp/ but if i do with with --server argument it gives the same error of @INC
      plackup -D -r --host 10.1.1.5 --port 8080 --user perl --access-log /va +r/log/psgi/access.log --max-requests 1000 --error-log /var/log/psgi/e +rror.log --server Starman --app myapp.psgi

        This is weird. It seems that Starman is doing something that prevents Config.pl from getting loaded, but I see no @INC manipulation. Starman inherits from Net::Server, which does some uid fiddling. Maybe when you're running plain plackup , the user does not get changed to perl, while with Starman, it gets changed?

        Consider checking the user permissions on Config.pl and all upper directories leading to it.

        Update: ... of course then, the error message should be Permission denied instead of File not found. So I'm still confused.

Re: Change cgi script to PSGI app
by Anonymous Monk on Sep 11, 2014 at 07:37 UTC
    run it in the background perl -e "  system 1, @ARGV " plackup  ...

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-16 13:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found