Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

pp: modules disappearing while program runs?

by sectokia (Pilgrim)
on Apr 06, 2022 at 22:31 UTC ( [id://11142756]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,

I have a weird problem:

I use pp on windows (with Strawberry perl) to make an exe for my program. This exe makes use of AnyEvent::HTTP which uses AnyEvent::Handle which uses New::SSLeay and AnyEvent::TLS. The exe is run via NonSuckingServiceManager as a background service. This program works fine most of the time. It can get HTTPS URLs using AnyEvent::HTTP and do its various things.

The problem I have is that after the exe has been waiting in a long AnyEvent->timer (often around 24 hours), when the timer triggers and the program wants to do more SSL GETs again.... they all fail with the error "TLS support not available on this system". The Error comes from this code in Any::Handle.pm in the starttls():

unless (defined $AnyEvent::TLS::VERSION) { eval { require Net::SSLeay; require AnyEvent::TLS; 1 } or return $self->_error (Errno::EPROTO, 1, "TLS support not av +ailable on this system"); }

What I don't understand is: How can the program 'work' for SSL GET, but hours later... this suddenly becomes unsupported?! Note the calls are even to the same SSL server....

The only thing I can think of is that pp unpacks to %temp% folder, so maybe windows is deleting temp files after some time, and so the 'require' in the eval starts to fail?

Does anyone know anything about this and how to avoid it? I sort of feel like one way around is for my program to kill itself every hour or so and let NSSM restart it (so pp unpacks again?), but I'm really clutching at straws here to identify the real issue.

Maybe another way to fix this is to 'use' the require modules in my own program so they are always in scope?

Any ideas? Thanks!

Replies are listed 'Best First'.
Re: pp: modules disappearing while program runs?
by swl (Parson) on Apr 07, 2022 at 03:04 UTC

    There can be issues with tools like CCleaner deleting temporary folders and thus any files in use by pp-packed executables that are not file-locked.

    Assuming that is the issue, the simplest option for now is to set the PAR_GLOBAL_TEMP environment variable to a folder that is not cleaned up automatically. This needs to be done before you start your program, e.g. by wrapping your code in a batch file or setting a system-wide env var. More details are at https://metacpan.org/dist/PAR/view/lib/PAR/Environment.pod.

    Re-running the executable is an option. This works because, when you re-run the executable, all the PAR archive contents are re-extracted if a canary file is not found. It is obviously clunkier but works.

      I tried using PAR_GLOBAL_TEMP, but the huge problem with it is that /par-USER/cache-XXXXXXX does not get added to the end of it, so *every* par packed EXE running on the system goes into the same directory (PAR_GLOBAL_TEMP) and rediculously bad things happen

      My *guess* is that I need to use PAR_TMPDIR ... but the documentation doesn't really say what it does, it just says use PAR_GLOBAL_TEMP instead.... *sigh*

        You can localise the settings by wrapping your executables inside batch files, setting the env vars in the batch files, and calling the batch files instead of the executables. Whether it is practical for your system is another question, of course.

        For example (untested):

        set PAR_GLOBAL_TEMP=C:\some\path exe_name.exe %*

        Another alternative it to write a wrapper script in perl that sets the environment and then calls the original exe. This script can be packed using pp, with the original exe added using --addfile. You will need logic in the wrapper script to determine if it is running under PAR and thus where it needs to look for the executable.

        # also untested use Path::Tiny qw /path/; use FindBin qw /$Bin/; my $exe_name = 'some_exe'; my $exe_path; if ($ENV{PAR_0}) { # running under PAR - look for the unpacked exe f +ile $exe_path = path ($ENV{PAR_TEMP}, 'inc', $exe_name)->stringify; } else { # not running under par, assume file is adjacent $exe_path = path( $Bin, $exe_name )->stringify; } # set the env var $ENV{GLOBAL_PAR_TEMP} = 'C:\some\path'; # now run it # maybe use exec or wrap it in Capture::Tiny::capture system $exe_path, @ARGV;

        Looking at the source... yeah there seems to be no way to do it. You would have to have a different PAR_GLOBAL_TEMP setting in the scope of every single exe that runs on the system... :-(

Re: pp: modules disappearing while program runs?
by salva (Canon) on Apr 07, 2022 at 11:14 UTC
    Check Win32::Packer (I am the author). Instead of creating a single executable, it creates a standard Windows installer (MSI) with all the dependencies.

    It has better support for detecting DLL dependencies than pp and it also does far less magical things than pp, so that you can check what gets installed and also use some tool as sysmon to see what the installed program does and when it fails find why!

    The bad news is that I am not maintaining that module any more... but it keeps working!

Re: pp: modules disappearing while program runs?
by choroba (Cardinal) on Apr 07, 2022 at 09:34 UTC
    Wait, if the requires have already run, they won't do anything when run for the second time. Under the same name, a module can only be loaded once.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      What if you delete the %INC entry (delete $INC{'Blah/Blah.pm'} for removing Blah::Blah) before the second require ... In my experiments (*), that allows me to have the require work again:

      ./lib/Blah/Blah.pm:

      package Blah::Blah; use 5.012; # strict, // use warnings; $| = 1; print "Loading Blah::Blah at " . scalar(localtime) . "\n"; 1;

      ./example.pl:

      #!perl use 5.012; # strict, // use warnings; use lib './lib'; $| = 1; require Blah::Blah; print "example separator\n"; delete $INC{'Blah/Blah.pm'}; print "entry deleted\n"; sleep(2); require Blah::Blah; print "example separator\n";

      output:

      Loading Blah::Blah at Thu Apr 7 06:17:19 2022 example separator entry deleted Loading Blah::Blah at Thu Apr 7 06:17:21 2022 example separator


      Edit: add footnote: *: well, at the command line; I admit I didn't try in a pp executable

        Yes. Also the require happening in a child/thread.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: pp: modules disappearing while program runs?
by sectokia (Pilgrim) on Apr 09, 2022 at 09:32 UTC
    So the solution that ended up seemingly working for me was just to 'use' those modules in my own scripts.
      Glad to hear it! Update the OP title so it says "solved"?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-03-29 12:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found