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

[solved] plack: close filehandle responsibility

by basiliscos (Pilgrim)
on May 05, 2015 at 17:21 UTC ( [id://1125754]=perlquestion: print w/replies, xml ) Need Help??

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

Solved! The root reason was in wrong DB-access: I use 'moo' to and always re-use the cached DB-connection, instead of creating new one on demand. (And "indirectly" closing it after serving the request). I actually used SQLite, so after heavy usage of it, it internally used filehandles and didn't closed them, so I got my error after some time.

Thanks all for answers.

The correct answer to my initial question is: indeed, I'm responsible for closing filehandle, but Path::Tiny does the right thing (DWIM) it closes the filehandle when it is no longer used; hence, my code sample provided here is valid.

Hello dear monks!

I'm using Kelp, which is very Plack-centered framework.

I have the following code for rendering icons:

use Path::Tiny; ... my $image = path($self->config('storage'), $domain_id, "icon-${size}.i +co"); ... return $self->res->set_content_type('image/x-icon') ->render_binary($image->filehandle('<', ':raw'));

After some time of execution under plackup I got the following error:

Error open (<:raw) on \'storage/3/icon-256.ico\': Too many open files at ...

Why so? I looked at Kelp::Request sources, and it just transfers the filehandle for Plack. Why Plack does not closes it after rendering the requests?

Yes, I know that I could do something like:

return $self->res->set_content_type('image/x-icon') ->render_binary($image->slurp);

but this is counter-effective a little bit? sendfile(2) cannot be used by server, and why at all I should load the whole image into perl, while actually i don't need it?

WBR, basiliscos.

Replies are listed 'Best First'.
Re: plack: close filehandle responsibility
by Anonymous Monk on May 05, 2015 at 18:29 UTC

    Too many open files ... Why so? I looked at Kelp::Request sources, and it just transfers the filehandle for Plack. Why Plack does not closes it after rendering the requests?

    Keep looking, don't stop, trace the code

    Or just report it to the developers

Re: plack: close filehandle responsibility
by Anonymous Monk on May 05, 2015 at 23:15 UTC
    If you want help here, please point to the specific line-range in "Kelp::Request" where "... it just transfers the filehandle." Be specific. Otherwise, it seems reasonable to ask the developer. This package is obviously being very-actively maintained, and he's probably very receptive to ideas about how his package should work.

      Hi , see sub response_cb in Plack::Util ... it closes handles

      I don't doubt basiliscos runs out of handles, I just think its his code that isn't closing them

Re: plack: close filehandle responsibility
by basiliscos (Pilgrim) on May 06, 2015 at 11:44 UTC

    Let me clarify the question: who is responsible for closing the filehandle? My code, framework (Kelp) or Plack?

    WBR, basiliscos.

      Let me clarify the question: who is responsible for closing the filehandle? My code, framework (Kelp) or Plack?

      Everybody is responsible :)

      You assume the problem is with Kelp or Plack but you haven't ruled out your own code; you always have to rule out your own code first

      If you can write a minimal Kelp app serving files that runs out of filehandles, only then can you assume there is a problem with Kelp or Plack, until then you should assume the problem is with your code

      The problem is not with Kelp::Response::render_binary as it doesn't leave handles open.

      It hands the handle to Plack::Response::body, and eventually sub response_cb in Plack::Util which reads from the handle and then closes the handle.

       

      On a side note, if don't already know, you should ignore flushells the troll

      Questions of this nature can be pretty-much categorically answered:   “it must be You!”

      • “Plack is a plumber,” solely responsible for getting a request delivered from Apache to you, and a subsequent response delivered from you to Apache.   No smoking-gun here...
      • Kelp, likewise, is a framework:   “generically” engineered to taking care of “whatever is ‘generic,’” so that you don’t have to.
      • ... which leaves:   you.   Your application must be prepared to handle many (thousands of?) requests without “leaking.”   (It can, to a certain extent, “take the easy way out” by asking the PSGI manager to arrange for you to “commit hari-kiri” after so-many requests, but that is a crutch.)   You should always assume that you are responsible for closing all resources.
Re: plack: close filehandle responsibility
by RonW (Parson) on May 06, 2015 at 20:44 UTC

    $image->filehandle('<', ':raw') is opening the file. And it is in your code. So, your code needs to close it.

    Not elegant (nor tested), but the following should work:

    my $ih = $image->filehandle('<', ':raw'); my $ret = $self->res->set_content_type('image/x-icon') ->render_binary($ih); close $ih; return $ret;

    Update: Rethinking this, the handle created by $image->filehandle and passed to render_binary() is being stored in some object. So, when that object gets destroyed, the handle should be automatically closed.

      Yes, that would close the filehandle before the file was sent, so no file would be sent

      See Re^2: plack: close filehandle responsibility (everybody), while https://metacpan.org/pod/Plack::Response#body doesn't document that it closes $io the handle it accepts as argument, it does do it

      Try it out, fireup this plack program, and start taskmanager, and watch the handles count not increase with each browser request you make

      #!/usr/bin/perl -- use strict; use warnings; use Plack::Builder; use Path::Tiny qw/ path /; my $app = sub { return [ 200, [ 'Content-Type' => 'text/plain; charset=UTF-8', ], path( __FILE__ )->openr_raw, ]; }; my $finalapp = builder { enable 'StackTrace'; $app; }; if( $0 eq __FILE__ ){ require Plack::Runner; my $runner = Plack::Runner->new; $runner->parse_options( qw' --host 127.0.0.1 --port 5000 ' ); $runner->run( $finalapp ); ## perl this.psgi } else { $finalapp; ## plackup -l localhost:5000 this.psgi } ## lwp-request -Ed http://127.0.0.1:5000/

      If I close the handle openr_raw returns before Plack reads it without slurping, there will probably be a plack error

      update: I just tested it, no error, but no file is sent either as expected

        I don't see where your code (in your response to my post) is calling render_binary().

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (9)
As of 2024-03-28 09:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found