How to use "Net::http" in Coro? - perl

Got stuck on using Net::HTTP
when i create a Net::HTTP object it initialize with "IO::Socket::IP".
how can i change default socket without hard-coding? I would like to change it to IO::Socket::INET.
So if i hard-code socket, it works.
But when i'm trying to use Coro::LWP and Coro::LWP changes IO::Socket::INET to Coro::Socket i got error:
Status read failed: Transport endpoint is not connected at perl5/lib/perl5/Net/HTTP/Methods.pm line 282.
I need to change socket because Clickhouse module on cpan doesn't support async requests.
here is code that doesn't work
use IO::Socket::INET qw( );
BEGIN { $Net::HTTP::SOCKET_CLASS = 'IO::Socket::INET'; };
use Coro::LWP;
my $s = Net::HTTP->new(Host => "www.perl.com") || die $#;
$s->write_request(GET => "/");
print $_ for ( $s->read_response_headers );
fixed!
just change Coro::Socket with Coro::PatchSet::Socket

You can't use IO::Socket::INET or IO::Socket::IP with Coro. Coro is a co-operative multi-threading system, so it only works with co-operating modules, and neither of these modules are Coro-aware. (By "work", I mean allow threads and asynchronous operations to progress.)
Among other things, Coro::LWP specifically makes Net::HTTP use Coro::LWP::Socket instead of IO::Socket::INET. Your attempts to make Net::HTTP use IO::Socket::IP are counter-productive.
You said you're switching the module because Clickhouse (by which I presume you meant ClickHouse) doesn't support async requests, but replacing IO::Socket::INET with IO::Socket::IP doesn't help with that at all.
Have you looked at AnyEvent::ClickHouse?

Related

How to fix Storable version discrepancy of a DBI Proxy connection?

I got a connection test script that is run on my client system and is calling a Perl DBI Proxy server via
my $dbh = DBI->connect("dbi:Proxy:$dbiproxy;dsn=$dsn", "$user","$pass",{ PrintError => 1}) || ($errmsg = "ERROR on connect");
When running the script it will fail stating
connect('hostname=***;port=2001;dsn=dbi:Oracle:***','***',...) failed: Cannot log in to DBI::ProxyServer: Unexpected EOF from server at /usr/local/share/perl/5.10.1/RPC/PlClient.pm line 79.
The log on the DBI Proxy server reads
Wed Dec 15 14:47:47 2015 err, Child died: Storable binary image v2.7 more recent than I am (v2.6) at blib/lib/Storable.pm (autosplit into blib/lib/auto/Storable/thaw.al) line 363, at /usr/lib/perl5/site_perl/5.8.0/RPC/PlServer/Comm.pm line 179
So I checked the Perl and Storable module version numbers of the two systems and the DBI proxy server seems to be rather outdated:
source: perl 5.10.1, storable 2.20, storable 2.7 (binary), Debian 6.0
target: perl 5.8.0 , storable 2.13, storable 2.6 (binary), RHEL 3
The problem is that I can not update the module/perl version of the target system, so I thought I could simply lower the utilized client version by modifying the /usr/local/share/perl/5.10.1/RPC/PlServer/Comm.pm file and change the line
require Storable;
to
use Storable 2.13;
but this will result in the same error as above. I also tried to use Storable 2.13 directly in my Perl test-script, but that does not change anything, either.
When googling this I could not find any solution, only confirmation that this version discrepancy can be a problem. Increasing the DBI_TRACE level on the client side also did not reveal anything new. Frankly I don't know what to try next and any help would be greatly appreciated.

Net::OpenSSH::Gateway->find_gateway fails when ControlPersist option is set

I am trying to create a persistent gateway connection using Net::OpenSSH::Gateway. Below is the code snippet I am using for the same.
my %proxy_opts = (
host => $host,
port=>$port,
password=>$password,
user=>$user ,
scheme=>"ssh",
ssh_cmd => '/usr/bin/ssh',
master_opts =>
[ -o=>"StrictHostKeyChecking=no",
-o=>"TCPKeepAlive=no",
-o=>"ServerAliveInterval=30",
-o=>"ServerAliveCountMax=90",
-o=>"ControlPath=/tmp/ssh-master-%h_%p_%r",
-o=>"ControlPersist=yes"
]
);
my %gateway_settings = ( proxies=>[ {%proxy_opts} ]);
my $gateway = Net::OpenSSH::Gateway->find_gateway(%gateway_settings, errors=>$errors);
I get the error below. But if I remove the option ControlPath and ControlPersist the entire thing works fine.
[ERROR ] unable to establish master SSH connection: bad ssh master at
/root/.libnet-openssh-perl/spangeni-j1.zscaler.-31930-744378, socket
owned by pid 31933 (pid 31931 expected)
I think it's a bug in the module. The module Net::OpenSSH::Gateway doesn't exist on CPAN, and the author already said that:
I have not published it on CPAN yet because, even it is already
functional, I have found some problems with its internal architecture
that I want to solve first. -Source
And also if you see the documentation of Net::OpenSSH you'll see that gateway is an experimental feature.
BTW what version of OpenSSH are you using? ControlPersist requires OpenSSH 5.6 or newer.
If you have tunnels enabled on the gateway machine, you don't need to use Net::OpenSSH::Gateway at all.
my $ssh_g=Net::OpenSSH->new($gateway);
my $proxy_command=$ssh_g->make_remote_command({tunnel => 1}, $host, 22);
my $ssh=Net::OpenSSH->new($host,
master_opts => [-o => "ProxyCommand=$proxy_command"]);

Arduino doesn't listen to data sent via virtual serial port until Serial Monitor has been opened

I have a BotBoarduino (a Duemilanove with a few extras) that I'm trying to communicate with using a Perl script. If I open the Serial Monitor from the Arduino IDE, I can send and receive data without a problem. Following this, my Perl script can communicate without any problems. However, if the Arduino is disconnected then reconnected to the PC, the Arduino doesn't seem to listen to commands sent from my Perl script until Serial Monitor is opened again.
I also tried using PuTTY to communicate with the Arduino, and this works the same way as Serial Monitor from the Arduino IDE - the Arduino doesn't listen to my Perl script until the connection has been opened once.
Here is a sample of the way I'm communicating with the Arduino using Perl:
#!perl -w
use Win32::SerialPort;
my $PortName = "COM4";
my $sendData = "c";
### SERIAL PORT SETUP ###
my $PortObj = new Win32::SerialPort($PortName) or die "Can't open $PortName: $^E\n";
$PortObj->baudrate(115200);
$PortObj->parity("none");
$PortObj->databits(8);
$PortObj->stopbits(1);
#$PortObj->dtr_active(1);
#$PortObj->rts_active(0);
#$PortObj->handshake("xoff");
$PortObj->lookclear();
$PortObj->write($sendData);
$PortObj->close();
I have commented out the dtr_active, rts_active and handshake bits. I played around with these settings as they were mentioned as possible culprits somewhere.
Also, I have used a 120 Ohm resistor to stop the Arduino from auto-resetting as described here.
Does anyone have any suggestions for the settings needed to get the Arduino to listen to my Perl program without having to open PuTTY/Serial Monitor first?
Turns out I wasn't saving the serial port settings, as described in a thread on the Arduino Forum. Adding $PortObj->write_settings(); after setting the serial port parameters got rid of the problem. My final Perl code that worked was:
#!perl -w
use Win32::SerialPort;
use strict;
use warnings;
$| = 1; #enable autoflush
my $PortName = "COM4";
my $sendData = "o";
### SERIAL PORT SETUP ###
my $PortObj = new Win32::SerialPort($PortName) or die "Can't open $PortName: $^E\n";
$PortObj->baudrate(57600);
$PortObj->parity("none");
$PortObj->databits(8);
$PortObj->stopbits(1);
$PortObj->write_settings(); #very important!
$PortObj->write($sendData);
$PortObj->close() || warn "\nClose failed\n";

LWP::UserAgent, mod_perl causing large Apache error logs

Each time LWP::UserAgent or LWP::Simple is used with mod_perl (PerlRun), Ubuntu 10.04.4 and Apache 2.2.14 I get about 50 or so error messages in the Apache error log:
Constant subroutine ModPerl::ROOT::ModPerl::PerlRun::home_user_public_html_index_2ecgi::RC_NOT_IMPLEMENTED redefined at /usr/lib/perl5/ModPerl/Util.pm line 69.
I have attempted defining the functions I will be using as:
use LWP::UserAgent qw(agent request);
However I am still getting these error messages. They are filling up the Apache error log very fast.
I think no warnings 'redefine'; will work.
use strict;
use warnings;
no warnings 'redefine';
Is how I usually do it.

how to solve 'Mysql2::Error: This connection is still waiting for a result' error with mysql2 and activerecord

Not duplicate of this question with the same title
I am using activerecord with mysql2 and I am designing to handle 10 queries to the same activerecord model/class at a time. Please note I am using strict activerecord and not using mysql queries directly.
I get the calls in Sinatra and then use activerecord to get the data from the DB.
I don't wan't the calls to be blocking so therefore I used mysql2 and I do NOT want to use em-synchrony.
But now I get the following "Mysql2::Error: This connection is still waiting for a result, try again once you have the result:" on subsequent simultanous calls.
I am not establishing connection with pool=10
my class
class User < ActiveRecord::Base
and my code to call
user.find(:all, :conditions => ["id=?", userid])
The mysql2 doc says "To use the ActiveRecord driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2". That was easy right? :)"
And that is exactly what I have done when I moved from mysql to mysql2.
Why am I getting this error.
Here is a fully working example:
require 'rubygems'
gem 'activerecord', '~> 3.1.0'
gem 'sinatra', '~> 1.3.1'
gem 'mysql2', '~> 0.3.11'
require 'active_record'
require 'sinatra/base'
require 'mysql2'
# thin use the eventmachine thread pool
# you should have at least one connection per thread
# or you can expect errors
EM::threadpool_size = 10
# connect to the database
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:database => "test",
:username => "root",
:encoding => 'utf8',
# number of connections openened to the database
:pool => 10
)
class App < Sinatra::Base
get '/db' do
ActiveRecord::Base.connection.execute("SELECT SLEEP(1)")
end
end
run App
to run it save the file as "config.ru" and run it with thin in threaded mode:
thin start -e production --threaded
You can use ab to check that everything is working, I used a tool called siege:
siege -c 10 -r 1 http://localhost:3000/db
You should use a ConnectionPool... Somehow you have 2 connections in a race condition.
I dont use Sinatra, I use Rails, but I had the same problem and solved it like that:
# class ActiveRecord::Base
# mattr_accessor :shared_connection
# ##shared_connection = nil
#
# def self.connection
# ##shared_connection || retrieve_connection
# end
# end
#
# ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
You have to use a connection pool. mysql2 allows the queries to be async, but you can still only send one query at a time to MySQL through one connection. If you send multiple queries through one connection you get the waiting for results message.
Use a connection pool and you should be fine.